「BZOJ2282」[SDOI2011] 消防
Description
某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000)。
这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。
现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。
你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。
Input
输入包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为城市的个数,s为路径长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
Output
输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。
Sample Input
「样例输入1」
5 2
1 2 5
2 3 2
2 4 4
2 5 3
「样例输出1」
5
「样例输入2」
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
「样例输出2」
5
HINT
「数据规模和约定」
对于20%的数据,n<=300。
对于50%的数据,n<=3000。
对于100%的数据,n<=300000,边长小等于1000。
题解
显然肯定是在直径上选一段,直径两次bfs可得
答案一定不会小于所有点到直径的距离最大值,只要把直径上的边权设为0,任选直径上一点bfs可得
将最大值作为二分下界,二分直径左右端点的舍弃部分
似乎不用二分也可以。。。但是二分比较直观一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
#include<cstdio> #include<cmath> #include<ctime> #include<cstring> #include<iostream> #include<algorithm> #define inf 1000000000 using namespace std; int read() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } int n,s,cnt,top,ans,D; int dis[300005],q[300005],st[300005],last[300005],from[300005]; bool mark[300005]; struct edge{ int to,next,v; }e[600005]; void insert(int u,int v,int w) { e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w; e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=w; } void bfs(int x) { for(int i=1;i<=n;i++)dis[i]=-1; int head=0,tail=1; q[0]=x;dis[x]=0; while(head!=tail) { int now=q[head];head++; for(int i=last[now];i;i=e[i].next) if(dis[e[i].to]==-1) { from[e[i].to]=now; if(mark[e[i].to])dis[e[i].to]=dis[now]; else dis[e[i].to]=dis[now]+e[i].v; q[tail++]=e[i].to; } } } bool jud(int D) { int l=1,r=top; while(st[1]-st[l+1]<=D&&l<=top)l++; while(st[r-1]<=D&&r>=1)r--; return st[l]-st[r]<=s; } int main() { n=read();s=read(); for(int i=1;i<n;i++) { int u=read(),v=read(),w=read(); insert(u,v,w); } int rt=0,x=0; bfs(1);for(int i=1;i<=n;i++)if(dis[i]>dis[rt])rt=i; bfs(rt);for(int i=1;i<=n;i++)if(dis[i]>dis[x])x=i; D=dis[x]; st[++top]=dis[x];mark[x]=1; while(x!=rt) { st[++top]=dis[from[x]],x=from[x]; mark[x]=1; } bfs(x); int l=0,r=D; for(int i=1;i<=n;i++)l=max(l,dis[i]); if(s<D) while(l<=r) { int mid=(l+r)>>1; if(jud(mid))r=mid-1; else l=mid+1; } printf("%d\n",l); return 0; } |
我比你机智
我比你机智
黄学长的程序能过样例吗
。。真的过不了样例
身败名裂。。。我看看
改了。。