[SDOI2011]消防

来源:互联网 发布:安卓串号修改软件 编辑:程序博客网 时间:2024/04/27 16:36

题目描述

某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000)。

这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。

现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。

你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。

输入输出格式

输入格式:

输入包含n行:

第1行,两个正整数n和s,中间用一个空格隔开。其中n为城市的个数,s为路径长度的上界。设结点编号以此为1,2,……,n。

从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。

输出格式:

输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。

输入输出样例

输入样例#1:
5 21 2 52 3 22 4 42 5 3
输出样例#1:
5
输入样例#2:
8 61 3 22 3 2 3 4 64 5 34 6 44 7 27 8 3
输出样例#2:
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_JUDGEfreopen("Thunder.in","r",stdin);freopen("Thunder.out","w",stdout);#endifn = 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;}