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考这种题还算良心。。。
代码:
View Code
View Code
题解:刚开始看见,卧槽这不是奶牛大集合吗,怎么出这种水题,两次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 }
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 }