[codeforces] 1004 E. Sonya and Ice Cream
题目链接:
题目大意:
给一个 个点的树,每一条边有一个长度 , 现在让你找出一最长长度为 条链, 使得链外的点到链上的最大距离最小能多小。
思路:
刚开始思路跑偏了, 忘记了题目中给定要求是找出一条链, 我以为最坏情况可以找出一棵子树。
首先可以确定的是要求出一条最长链, 对于链上的每一个点求出这个点不在链上的最长向外延伸的长度, 那么我们要维护一个长度为k的链, 对于链上的点就分为两种情况。
- 最长链上的点在所选链的范围内, 那么他对答案产生的影响就是这个点向外延伸的长度
- 每次都求出最长链两端没有被选择的长度。
最长链中选择长度为k的子链, 两边的长度很好维护, 需要考虑的是被选中的这k个点向外延伸的最长长度, 这个时候就可以用单调队列维护。
整个题的思路就是先跑出最长链, 把链上的所有点以及每个点到链头的长度维护出来。
之后再对链上的每一个点求出向链外延伸的最长长度。
之后便是扫一遍链上每一个点, 使用单调队列维护区间内的向外延伸最长长度。
AC代码
/********************************************
*Author* :ZZZZone
*Created Time* : 2018年07月09日 星期一 20时41分46秒
* Ended Time* : 2018年07月09日 星期一 20时58分57秒
*********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
inline void OPEN(string s){
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
const int MAXN = 1e5;
int n, k;
vector<PII> edge[MAXN+5];
int dis[MAXN+5], pre[MAXN+5];
bool vis[MAXN+5];
void Init(){
scanf("%d %d", &n, &k);
for(int i = 1; i < n; i++){
int u ,v, c;
scanf("%d %d %d", &u, &v, &c);
edge[u].push_back(PII(v, c));
edge[v].push_back(PII(u, c));
}
}
void Dfs(int u, int fa, int& Max_len){
Max_len = max(Max_len, dis[u]);
pre[u] = fa;
for(int i = 0; i < edge[u].size(); i++){
int v = edge[u][i].first;
int cost = edge[u][i].second;
if(vis[v] || v == fa) continue;
dis[v] = dis[u] + cost;
Dfs(v, u, Max_len);
}
}
void Solve(){
dis[1] = 0;
int Max_len = 0;
Dfs(1, 0, Max_len);
int st = 1, ed = 1;
for(int i = 1; i <= n; i++){
if(dis[i] > dis[st]) st = i;
}
dis[st] = 0;
Dfs(st, 0, Max_len);
for(int i = 1; i <= n; i++){
if(dis[i] > dis[ed]) ed = i;
}
vector<int> dia, len, dep;
while(ed){
dia.push_back(ed);
len.push_back(dis[ed]);
vis[ed] = true;
ed = pre[ed];
}
reverse(dia.begin(), dia.end());
reverse(len.begin(), len.end());
int tot = (int)dia.size();
k = min(k ,tot);
for(int i = 0; i < tot; i++){
dis[dia[i]] = Max_len = 0;
Dfs(dia[i], 0, Max_len);
dep.push_back(Max_len);
}
int res = 1 << 30;
deque<PII> dque;// 双端队列实现单调队列
for(int i = 0, j = 0; i + k <= tot; i++){
while(j < i + k){
while(!dque.empty() && dque.back().first < dep[j]){
dque.pop_back();
}
dque.push_back(PII(dep[j], j));
j++;
}
while(dque.front().second < i) dque.pop_front();
res = min(res , max(len[i], max(len.back() - len[i+k-1], dque.front().first)));
}
printf("%d\n", res);
}
int main()
{
Init();
Solve();
return 0;
}