bzoj2282[Sdoi2011]消防

bzoj2282[Sdoi2011]消防

题意:

在树上找一条路径,使得端点到这条路径的距离最大值最小。

题解:

一个坑,就是这个路径可以不包含任意一条边,只包含一个节点。因此可以证明这条路径在树的直径上,把树的直径上的所有边存入一个序列,对直径上每个点求其它不在路径上的点与它的最大距离mxd,然后用双指针维护序列的一段使得和≤s,比较答案和序列两端到直径首末端的距离及序列中的点的最大mxd的较大值。序列中的点的最大mxd值用单调队列即可维护,怎么求树的直径呢?先对任意节点dfs/bfs求出最大距离的点,再对这个点作dfs/bfs求出与其距离最大的点,第二次遍历到第二个点所经过的路径就是树的直径。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 300010
 6 using namespace std;
 7 
 8 inline int read(){
 9     char ch=getchar(); int f=1,x=0;
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
11     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
12     return f*x;
13 }
14 int n,s,d[maxn],f[maxn],p[maxn],ed[maxn],mxd[maxn],tot,fr,ta,q1[maxn],q2[maxn],l,r,now,ans,sm[maxn];
15 bool vis[maxn];
16 struct e{int t,w,n;}; e es[maxn*3]; int g[maxn],ess;
17 void pe(int f,int t,int w){
18     es[++ess]=(e){t,w,g[f]}; g[f]=ess; es[++ess]=(e){f,w,g[t]}; g[t]=ess;
19 }
20 void dfs1(int x,int fa){
21     for(int i=g[x];i;i=es[i].n)if(es[i].t!=fa)d[es[i].t]=d[x]+es[i].w,dfs1(es[i].t,x);
22 }
23 void dfs2(int x){
24     for(int i=g[x];i;i=es[i].n)if(i!=f[x])d[es[i].t]=d[x]+es[i].w,f[es[i].t]=i^1,dfs2(es[i].t);
25 }
26 void dfs3(int x){
27     for(int i=g[x];i;i=es[i].n)if(!vis[es[i].t])
28         d[es[i].t]=d[x]+es[i].w,mxd[0]=max(mxd[0],d[es[i].t]),vis[es[i].t]=1,dfs3(es[i].t);
29 }
30 int main(){
31     n=read(); s=read(); ess=1; inc(i,1,n-1){int a=read(),b=read(),c=read(); pe(a,b,c);}
32     d[1]=0; dfs1(1,0); int mx1=1; inc(i,1,n)if(d[i]>d[mx1])mx1=i; d[mx1]=0; f[mx1]=0; dfs2(mx1);
33     int mx2=mx1; inc(i,1,n)if(d[i]>d[mx2])mx2=i;
34     for(int i=mx2;i;i=es[f[i]].t)tot++,p[tot]=i,ed[tot]=es[f[i]].w,vis[i]=1;
35     inc(i,1,tot)d[p[i]]=0,mxd[0]=0,dfs3(p[i]),mxd[i]=mxd[0],sm[i]=sm[i-1]+ed[i];
36     l=1; r=1; now=ed[1]; fr=ta=1; q1[1]=mxd[1]; q2[1]=1; ans=0x3fffffff;
37     while(l<=r&&l<=tot-1){
38         while(r<=tot-1&&now<=s){
39             ans=min(ans,max(max(q1[fr],sm[l-1]),sm[tot-1]-sm[r-1])); r++;
40             while(fr<=ta&&mxd[r]>q1[ta])ta--; q1[++ta]=mxd[r]; q2[ta]=r; now+=ed[r];
41         }
42         if(q2[fr]==l)fr++; now-=ed[l]; l++;
43         if(l<=tot-1&&now<=s)ans=min(ans,max(max(q1[fr],sm[l-1]),sm[tot-1]-sm[r]));
44     }
45     inc(i,1,tot)ans=min(ans,max(max(mxd[i],sm[i-1]),sm[tot-1]-sm[i-1]));
46     printf("%d",ans); return 0;
47 }

 

20160715

posted @ 2016-07-15 22:24  YuanZiming  阅读(403)  评论(0编辑  收藏  举报