[SDOI2011]消防
题目大意:
给你一棵n个结点的带边权的树,让你找出一条长度不超过s的链,使得结点到链的最大距离最小,求这个距离的最小值。
思路:
不难发现链在直径上的情况一定是最优的。
首先找出这个直径,然后二分答案m。
对于每一个m,把直径往里缩,使得两边缩的长度<=m。
判断一下缩完以后的直径是不是<=s。
二分的下界为结点到直径距离的最大值,上界为直径的长度。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=300001; 13 struct Edge { 14 int to,w; 15 }; 16 std::vector<Edge> e[N]; 17 inline void add_edge(const int &u,const int &v,const int &w) { 18 e[u].push_back((Edge){v,w}); 19 e[v].push_back((Edge){u,w}); 20 } 21 bool vis[N],mark[N]; 22 int n,s,dis[N],from[N],stack[N]; 23 std::queue<int> q; 24 inline bool check(const int &m) { 25 int l=1,r=stack[0]-1; 26 while(stack[1]-stack[l+1]<=m&&l<stack[0]) l++; 27 while(stack[r-1]<=m&&r) r--; 28 return stack[l]-stack[r]<=s; 29 } 30 int main() { 31 n=getint(),s=getint(); 32 for(register int i=1;i<n;i++) { 33 const int u=getint(),v=getint(),w=getint(); 34 add_edge(u,v,w); 35 } 36 int d=0,u=0,v=0; 37 q.push(1); 38 dis[1]=0; 39 vis[1]=true; 40 while(!q.empty()) { 41 const int x=q.front(); 42 q.pop(); 43 if(dis[x]>d) { 44 d=dis[x]; 45 u=x; 46 } 47 for(register unsigned i=0;i<e[x].size();i++) { 48 const int &y=e[x][i].to,&w=e[x][i].w; 49 if(vis[y]) continue; 50 q.push(y); 51 dis[y]=dis[x]+w; 52 vis[y]=true; 53 } 54 } 55 d=0; 56 q.push(u); 57 dis[u]=0; 58 vis[u]=false; 59 while(!q.empty()) { 60 const int x=q.front(); 61 q.pop(); 62 if(dis[x]>d) { 63 d=dis[x]; 64 v=x; 65 } 66 for(register unsigned i=0;i<e[x].size();i++) { 67 const int &y=e[x][i].to,&w=e[x][i].w; 68 if(!vis[y]) continue; 69 q.push(y); 70 dis[y]=dis[x]+w; 71 vis[y]=false; 72 from[y]=x; 73 } 74 } 75 for(register int x=v;x;x=from[x]) { 76 mark[x]=true; 77 stack[++stack[0]]=dis[x]; 78 } 79 q.push(u); 80 dis[u]=0; 81 vis[u]=true; 82 while(!q.empty()) { 83 const int x=q.front(); 84 q.pop(); 85 for(register unsigned i=0;i<e[x].size();i++) { 86 const int &y=e[x][i].to,&w=e[x][i].w; 87 if(vis[y]) continue; 88 q.push(y); 89 if(mark[y]) { 90 dis[y]=0; 91 } else { 92 dis[y]=dis[x]+w; 93 } 94 vis[y]=true; 95 from[y]=x; 96 } 97 } 98 int l=0,r=d; 99 for(register int i=1;i<=n;i++) { 100 l=std::max(l,dis[i]); 101 } 102 while(l<=r) { 103 const int mid=(l+r)/2; 104 if(check(mid)) { 105 r=mid-1; 106 } else { 107 l=mid+1; 108 } 109 } 110 printf("%d\n",r+1); 111 return 0; 112 }