[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;
}