题目描述
某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000)。
这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。
现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。
你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。
输入输出格式
输入格式:输入包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为城市的个数,s为路径长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
输出格式:输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。
输入输出样例
5 2 1 2 5 2 3 2 2 4 4 2 5 3
5
8 6 1 3 2 2 3 2 3 4 6 4 5 3 4 6 4 4 7 2 7 8 3
5
说明
【数据规模和约定】
对于20%的数据,n<=300。
对于50%的数据,n<=3000。
对于100%的数据,n<=300000,边长小等于1000。
可以發現,這條路只可能在直徑上,因此,我們只需在直徑上看選哪一段即可
我們可以用一個隊列加set維護每次儘量選長度迫近s的路,O(n)掃過去,總複雜度O(n),set的複雜度由於實在直徑上掃可忽略不計
當然還要預處理一些東西,從這個點網直徑外的其他點搜的最大長度,以這個點爲路徑起點前面的所有點到這個點的最大路經長,以這個點爲路徑終點後面的點到這個點的最大路徑長度,就可以了,可能有更簡潔的寫法,但是我一有思路就上了,代碼可能有些冗長,不過關鍵還是思路吧
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 600010;
int n, s, Begin[maxn], to[maxn], Next[maxn], e, w[maxn];
int read(){
int sum = 0,fg = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-')fg = -1;c = getchar();}
while(c >='0' && c <='9')sum = (sum<<1) + (sum<<3) + c-'0',c = getchar();
return sum * fg;
}
void add(int x,int y,int z){
to[++e] = y;
Next[e] = Begin[x];
Begin[x] = e;
w[e] = z;
}
int dis[maxn], max_dis, pos, fa[maxn], q[maxn], Max[maxn], p[maxn], id[maxn];
void dfs(int h,int father){
for(int i = Begin[h];i ;i = Next[i]){
int v = to[i];
if(v != father){
fa[v] = h;
dis[v] = dis[h] + w[i];
id[v] = i;
dfs(v, h);
}
}
if(dis[h] > max_dis)max_dis = dis[h], pos = h;
}
void _dfs(int h,int father,int tmp){
for(int i = Begin[h];i ;i = Next[i]){
int v = to[i];
if(v != father && !p[v]){
dis[v] = dis[h] + w[i];
_dfs(v, h, tmp);
}
}
Max[tmp] = max(Max[tmp], dis[h]);
}
int ls[maxn], cnt, nowmax[maxn], quan[maxn], _nowmax[maxn], ans = inf;
struct node{
int value;
node(){
value = 0;
}
};
set<node> se;
set<node>::iterator it;
bool operator < (node c,node d){
return c.value > d.value;
}
void done(int tmp){
int u = pos,v = tmp;
while(u != v){
p[u] = 1;
u = fa[u];
}
p[u] = 1;
u = pos, v = tmp;
while(u != v){
dis[u] = 0;
_dfs(u, -1, u);
u = fa[u];
}
dis[u] = 0;
_dfs(u, -1, u);
u = pos, v = tmp;
while(u != v){
ls[++cnt] = u;
quan[cnt] = w[id[u]];
u = fa[u];
}
ls[++cnt] = u;
int t = Max[u];
nowmax[u] = Max[u];
for(int i = cnt-1;i >= 1; --i){
int now = ls[i];
t = max(t + w[id[now]], Max[now]);
nowmax[now] = t;
}
t = Max[1];
_nowmax[ls[1]] = t;
for(int i = 2;i <= cnt; ++i){
int now = ls[i];
t = max(t + w[id[ls[i-1]]], Max[now]);
_nowmax[now] = t;
}
int l = 1,r = 0,tot = 0,maxnow = 0;
q[++r] = 1;
int gross = max(_nowmax[tmp], nowmax[tmp]);
ans = min(ans, gross);
node T;
T.value = Max[1];
se.insert(T);
for(int i = 2;i <= cnt; ++i){
while(l <= r && tot + quan[i-1] > s){
T.value = Max[ls[q[l]]];
se.erase(T);
tot -= quan[q[l]];
++ l;
}
tot += quan[i-1];
T.value = nowmax[ls[i]];
se.insert(T);
T.value = Max[ls[i]];
se.insert(T);
if(l <= r){
T.value = _nowmax[ls[q[l]]];
se.insert(T);
it = se.begin();
node tt = *it;
ans = min(ans, tt.value);
se.erase(T);
}
else{
T.value = _nowmax[ls[i]];
se.insert(T);
it = se.begin();
node tt = *it;
se.erase(T);
ans = min(ans, tt.value);
}
T.value = nowmax[ls[i]];
se.erase(T);
q[++r] = i;
}
printf("%d\n", ans);
}
void solve(){
dis[1] = 0;
dfs(1, -1);
int tmp = pos;
dis[tmp] = 0;
max_dis = 0;
fa[tmp] = 0;
dfs(tmp, -1);
done(tmp);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Thunder.in","r",stdin);
freopen("Thunder.out","w",stdout);
#endif
n = read(),s = read();
for(int i = 1;i < n; ++i){
int x = read(),y = read(),z = read();
add(x, y, z), add(y, x, z);
}
solve();
return 0;
}