NOIP 2007 树网的核

题意

哇,太长了。

题解

显然,树的直径不唯一但一定相交并且各个·直径的中点汇聚于同一处。

进一步得到一个推论,任意一个直径上求出的偏心距都相等。

原题中(n<=100)我们发现n的范围有点小。直接上暴力。

floyed预处理一下。找到树的直径。

暴力枚举树网的核再暴力枚举偏心距(至于具体怎么枚举看代码)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 int n,s,f[305][305],ans=999999999;
 8 int main(){
 9     scanf("%d%d",&n,&s);
10     memset(f,0x3f,sizeof(f));
11     for(int i=1;i<=n;i++){
12         f[i][i]=0;
13     }
14     for(int i=1,u,v,w;i<=n-1;i++){
15         scanf("%d%d%d",&u,&v,&w);
16         f[u][v]=f[v][u]=w;
17     }
18     for(int x=1;x<=n;x++)
19         for(int i=1;i<=n;i++)
20             for(int j=1;j<=n;j++){
21                 f[i][j]=min(f[i][j],f[i][x]+f[x][j]);
22             }
23     int l,r,maxx=0;
24     for(int i=1;i<=n;i++)
25         for(int j=1;j<=n;j++){
26             if(f[i][j]>maxx){
27                 maxx=f[i][j];
28                 l=i;
29                 r=j;
30             }
31         }
32     for(int i=1;i<=n;i++)
33         for(int j=1;j<=n;j++){
34             if(f[i][j]<=s&&f[l][i]+f[i][j]+f[j][r]==f[l][r]){
35                 int tmp=0;
36                 for(int x=1;x<=n;x++){
37                     tmp=max(tmp,(f[x][i]+f[x][j]-f[i][j])/2);
38                 }
39                 ans=min(ans,tmp);
40             }
41         }
42     printf("%d",ans);
43     return 0; 
44 }
View Code

但是当(n<=300000 SDOI2011消防)时以上的做法就GG了。需要考虑更优的方法。
考虑二分。(核越靠近中点答案越大)。对于我们二分的mid我们找到距离直径的两端距离大于等于mid的两点p,q之间的路径作为偏心距,判断是否成立即可。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 #define N 300005
  6 
  7 int n,s,x,y,z,Max,dMax,pt,inf,ans;
  8 int tot,point[N],nxt[N*2],v[N*2],c[N*2];
  9 int h[N],father[N],edge[N],leaf[N],C[N],len[N],goal[N],dis[N];
 10 bool is[N];
 11 
 12 void add(int x,int y,int z)
 13 {
 14     ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
 15 }
 16 void dfs(int x,int fa,int dep)
 17 {
 18     father[x]=fa;h[x]=dep;
 19     if (h[x]>Max)
 20     {
 21         Max=h[x],pt=x;
 22     }
 23     bool flag=false;
 24     for (int i=point[x];i;i=nxt[i])
 25         if (v[i]!=fa)
 26         {
 27             dfs(v[i],x,dep+c[i]),flag=true;
 28             edge[v[i]]=c[i];
 29         }
 30     if (!flag) leaf[++leaf[0]]=x;
 31 }
 32 void chain(int x)
 33 {
 34     while (h[x]!=0)
 35     {
 36         is[x]=true;
 37         C[++C[0]]=x;
 38         x=father[x];
 39     }
 40     C[++C[0]]=x;is[x]=true;
 41 }
 42 void length(int x,int fa,int dep,int st)
 43 {
 44     dis[st]=max(dis[st],dep);
 45     for (int i=point[x];i;i=nxt[i])
 46         if (v[i]!=fa&&!is[v[i]])
 47             length(v[i],x,dep+c[i],st);
 48 }
 49 bool check(int mid)
 50 {
 51     for (int i=1;i<=C[0];++i)
 52         if (dis[C[i]]<=mid) len[C[i]]=dis[C[i]]-mid;
 53         else return false;
 54 
 55     len[C[1]]=len[C[C[0]]]=mid;
 56     for (int i=1;i<=C[0];++i)
 57         if (len[C[i]]>=edge[C[i]])
 58         {
 59             len[C[i+1]]=min(len[C[i+1]],len[C[i]]-edge[C[i]]);
 60             len[C[i]]=inf;
 61         }
 62         else break;
 63     for (int i=C[0];i>=1;--i)
 64         if (len[C[i]]>=edge[C[i-1]])
 65         {
 66             len[C[i-1]]=min(len[C[i-1]],len[C[i]]-edge[C[i-1]]);
 67             len[C[i]]=inf;
 68         }
 69         else break;
 70     int l=0,a=0,b=0;
 71     for (int i=1;i<=C[0];++i)
 72         if (len[C[i]]!=inf) {a=i;break;}
 73     for (int i=C[0];i>=1;--i)
 74         if (len[C[i]]!=inf) {b=i;break;}
 75     for (int i=a;i<b;++i) l+=edge[C[i]];
 76     if (l<=s) return true;
 77     else return false;
 78 }
 79 int find()
 80 {
 81     int l=0,r=dMax,mid,ans;
 82     while (l<=r)
 83     {
 84         mid=(l+r)>>1;
 85         if (check(mid)) ans=mid,r=mid-1;
 86         else l=mid+1;
 87     }
 88     return ans;
 89 }
 90 int main()
 91 {
 92     scanf("%d%d",&n,&s);
 93     for (int i=1;i<n;++i)
 94     {
 95         scanf("%d%d%d",&x,&y,&z);
 96         add(x,y,z);add(y,x,z);dMax+=z;
 97     }
 98     dfs(1,0,0);
 99     leaf[0]=1,h[pt]=0,Max=0,edge[pt]=0,dfs(pt,0,0);
100     chain(pt);
101     memset(len,127,sizeof(len));inf=len[0];
102     for (int i=1;i<=C[0];++i)
103         length(C[i],0,0,C[i]);
104     ans=find();
105     printf("%d\n",ans);
106 }
View Code

 

posted @ 2018-07-28 12:01  Xu-daxia  阅读(233)  评论(0编辑  收藏  举报