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