BZOJ3743: [Coci2014]Kamp

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3743

一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。
有K个人(分布在K个不同的点)要集中到一个点举行聚会。
聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。
请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。
K <= N <= 500000
1 <= x,y <= N, 1 <= z <= 1000000
题解:刚开始看见,卧槽这不是奶牛大集合吗,怎么出这种水题,两次DFS搞定。
         下午来了打完代码发现居然是一辆车送多个奶牛,然后想到了up和down,然后又开始写。
          写完发现车可以停在任意一个点,那就是由i点出发到达有奶牛的点的最长链哦,好像也是两次DP?保留一个最优值和次优值。然后写完就A了。。。
         需要注意一点,就是只能用子节点的最优值去更新父节点的值,而不能用次优值,因为这可能导致父节点的最优值和次优值都是该子树内的。。。
         貌似NOIP考这种题还算良心。。。
代码:
  1 #include<cstdio>
  2 
  3 #include<cstdlib>
  4 
  5 #include<cmath>
  6 
  7 #include<cstring>
  8 
  9 #include<algorithm>
 10 
 11 #include<iostream>
 12 
 13 #include<vector>
 14 
 15 #include<map>
 16 
 17 #include<set>
 18 
 19 #include<queue>
 20 
 21 #include<string>
 22 
 23 #define inf 1000000000
 24 
 25 #define maxn 500000+5
 26 
 27 #define maxm 500+100
 28 
 29 #define eps 1e-10
 30 
 31 #define ll long long
 32 
 33 #define pa pair<int,int>
 34 
 35 #define for0(i,n) for(int i=0;i<=(n);i++)
 36 
 37 #define for1(i,n) for(int i=1;i<=(n);i++)
 38 
 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 40 
 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 42 
 43 #define mod 1000000007
 44 
 45 using namespace std;
 46 
 47 inline int read()
 48 
 49 {
 50 
 51     int x=0,f=1;char ch=getchar();
 52 
 53     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 54 
 55     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 56 
 57     return x*f;
 58 
 59 }
 60 struct edge{int go,next;ll w;}e[2*maxn];
 61 int n,m,tot,s[maxn],head[maxn];
 62 ll f[maxn],g[maxn],z[maxn][2];
 63 bool v[maxn],a[maxn];
 64 inline void insert(int x,int y,int z)
 65 {
 66     e[++tot]=edge{y,head[x],z};head[x]=tot;
 67     e[++tot]=edge{x,head[y],z};head[y]=tot;
 68 }
 69 inline void down(int x)
 70 {
 71     v[x]=1;s[x]=a[x];
 72     for(int i=head[x],y;i;i=e[i].next)
 73         if(!v[y=e[i].go])
 74         {
 75             down(y);
 76             s[x]+=s[y];
 77             if(s[y])g[x]+=g[y]+e[i].w*2;
 78         }
 79     v[x]=0;    
 80 }
 81 inline void up(int x)
 82 {
 83     v[x]=1;
 84     for(int i=head[x],y;i;i=e[i].next)
 85         if(!v[y=e[i].go])
 86         {
 87             if(s[y]!=m)
 88             {
 89                 if(s[y])f[y]=f[x]+g[x]-g[y];else f[y]=f[x]+g[x]-g[y]+2*e[i].w;
 90             }
 91             up(y);
 92         }
 93     v[x]=0;
 94 }
 95 inline void update(int y,int x)
 96 {
 97     if(y>z[x][0]){z[x][1]=z[x][0];z[x][0]=y;}
 98     else if(y>z[x][1])z[x][1]=y;
 99 }
100 inline void dp1(int x)
101 {
102     v[x]=1;
103     for(int i=head[x],y;i;i=e[i].next)
104     if(!v[y=e[i].go])
105     {
106         dp1(y);
107         if(s[y])update(z[y][0]+e[i].w,x);//update(z[y][1]+e[i].w,x);
108     }
109     v[x]=0;
110 }
111 inline void dp2(int x)
112 {
113     v[x]=1;
114     for(int i=head[x],y;i;i=e[i].next)
115     if(!v[y=e[i].go])
116     {
117         if(z[x][0]==z[y][0]+e[i].w)update(z[x][1]+e[i].w,y);
118         else update(z[x][0]+e[i].w,y);
119         dp2(y);
120     }
121     v[x]=0;
122 }
123 
124 int main()
125 
126 {
127 
128     freopen("input.txt","r",stdin);
129 
130     freopen("output.txt","w",stdout);
131 
132     n=read();m=read();
133     for1(i,n-1){int x=read(),y=read();insert(x,y,read());}
134     for1(i,m)a[read()]=1;
135     down(1);
136     up(1);
137     dp1(1);
138     dp2(1);
139     //for1(i,n)printf("%d %d %d %d\n",i,f[i],g[i],z[i][0]);
140     for1(i,n)printf("%lld\n",f[i]+g[i]-z[i][0]);
141 
142     return 0;
143 
144 }
View Code

 UPD:上面写的求从一个点出发到奶牛点的最长距离写萎了。。。

 正确的姿势应该是z[x][0/1]表示x向下的最长和次长,然后d[x]表示先向上一步的最长链。

这样:

inline void dp2(int x)
{
    v[x]=1;
    for(int i=head[x],y;i;i=e[i].next)
    if(!v[y=e[i].go])
    {
        d[y]=max(d[y],d[x]+e[i].w);
        if(z[x][0]==z[y][0]+e[i].w)d[y]=max(d[y],z[x][1]+e[i].w);
        else d[y]=max(d[y],z[x][0]+e[i].w);
        dp2(y);
    }
    v[x]=0;
}

然后就对了。。。233不知道原来怎么A的。。。

代码:

  1 #include<cstdio>
  2 
  3 #include<cstdlib>
  4 
  5 #include<cmath>
  6 
  7 #include<cstring>
  8 
  9 #include<algorithm>
 10 
 11 #include<iostream>
 12 
 13 #include<vector>
 14 
 15 #include<map>
 16 
 17 #include<set>
 18 
 19 #include<queue>
 20 
 21 #include<string>
 22 
 23 #define inf 1000000000
 24 
 25 #define maxn 500000+5
 26 
 27 #define maxm 500+100
 28 
 29 #define eps 1e-10
 30 
 31 #define ll long long
 32 
 33 #define pa pair<int,int>
 34 
 35 #define for0(i,n) for(int i=0;i<=(n);i++)
 36 
 37 #define for1(i,n) for(int i=1;i<=(n);i++)
 38 
 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 40 
 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 42 
 43 #define mod 1000000007
 44 
 45 using namespace std;
 46 
 47 inline int read()
 48 
 49 {
 50 
 51     int x=0,f=1;char ch=getchar();
 52 
 53     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 54 
 55     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 56 
 57     return x*f;
 58 
 59 }
 60 struct edge{int go,next;ll w;}e[2*maxn];
 61 int n,m,tot,s[maxn],head[maxn];
 62 ll f[maxn],g[maxn],z[maxn][2],d[maxn];
 63 bool v[maxn],a[maxn];
 64 inline void insert(int x,int y,int z)
 65 {
 66     e[++tot]=edge{y,head[x],z};head[x]=tot;
 67     e[++tot]=edge{x,head[y],z};head[y]=tot;
 68 }
 69 inline void down(int x)
 70 {
 71     v[x]=1;s[x]=a[x];
 72     for(int i=head[x],y;i;i=e[i].next)
 73         if(!v[y=e[i].go])
 74         {
 75             down(y);
 76             s[x]+=s[y];
 77             if(s[y])g[x]+=g[y]+e[i].w*2;
 78         }
 79     v[x]=0;    
 80 }
 81 inline void up(int x)
 82 {
 83     v[x]=1;
 84     for(int i=head[x],y;i;i=e[i].next)
 85         if(!v[y=e[i].go])
 86         {
 87             if(s[y]!=m)
 88             {
 89                 if(s[y])f[y]=f[x]+g[x]-g[y];else f[y]=f[x]+g[x]-g[y]+2*e[i].w;
 90             }
 91             up(y);
 92         }
 93     v[x]=0;
 94 }
 95 inline void update(int y,int x)
 96 {
 97     if(y>z[x][0]){z[x][1]=z[x][0];z[x][0]=y;}
 98     else if(y>z[x][1])z[x][1]=y;
 99 }
100 inline void dp1(int x)
101 {
102     v[x]=1;
103     for(int i=head[x],y;i;i=e[i].next)
104     if(!v[y=e[i].go])
105     {
106         dp1(y);
107         if(s[y])update(z[y][0]+e[i].w,x);//update(z[y][1]+e[i].w,x);
108     }
109     v[x]=0;
110 }
111 inline void dp2(int x)
112 {
113     v[x]=1;
114     for(int i=head[x],y;i;i=e[i].next)
115     if(!v[y=e[i].go])
116     {
117         d[y]=max(d[y],d[x]+e[i].w);
118         if(z[x][0]==z[y][0]+e[i].w)d[y]=max(d[y],z[x][1]+e[i].w);
119         else d[y]=max(d[y],z[x][0]+e[i].w);
120         dp2(y);
121     }
122     v[x]=0;
123 }
124 
125 int main()
126 
127 {
128 
129     freopen("input.txt","r",stdin);
130 
131     freopen("output.txt","w",stdout);
132 
133     n=read();m=read();
134     for1(i,n-1){int x=read(),y=read();insert(x,y,read());}
135     for1(i,m)a[read()]=1;
136     down(1);
137     up(1);
138     dp1(1);
139     dp2(1);
140     //for1(i,n)printf("%d %d %d %d\n",i,f[i],g[i],z[i][0]);
141     for1(i,n)printf("%lld\n",f[i]+g[i]-max(d[i],z[i][0]));
142 
143     return 0;
144 
145 }
View Code

 

posted @ 2014-11-12 17:22  ZYF-ZYF  Views(416)  Comments(0Edit  收藏  举报