[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 }

 

posted @ 2017-12-21 15:06  skylee03  阅读(87)  评论(0编辑  收藏  举报