Bzoj1917 [Ctsc2010]星际旅行
Submit: 185 Solved: 118
Description
公元3000年,地球联盟已经攻占了银河系内的N个星球,出于资金的考虑,政府仅仅在星球间建立了N-1条双向时空隧道保证任意两个星球之间互相可达。出于管理上的考虑,第i个星球的行政长官要求每个公民在一年内不得从该星球利用时空隧道次数超过Hi次(这一统计是基于离开次数统计的,如果你已经使用从该星球离开过Hi次,那么这一年内你就不能再使用时空隧道离开这个星球了)。Louis Paosen是一个星际旅行家,他希望能使用尽量多次的时空隧道,但又不希望最终被迫定居的星球条件太过恶劣。所以他希望能知道对于每个星球i,若从0号星球出发,最终以i号星球为终点,这样的星际旅行途中最多可以使用多少次时空隧道。
Input
第一行包含一个整数N。接下来的一行包含N个整数Hi,分别表示每个星球的离开次数限制。接下来N-1行每行两个整数,表示这两个星球之间有时空隧道连接。星球的编号从0开始,Louis Paosen一开始在0号星球。
Output
包含N行,每行一个整数,表示如果最终旅行结束在这个星球,最多可以使用时空隧道的次数。
Sample Input
3
2 6 2
0 1
1 2
2 6 2
0 1
1 2
Sample Output
8
7
8
7
8
HINT
40%的数据N≤500
100%的数据中N≤50000。
所有星球的离开次数限制满足1≤Hi≤40000,且每个星球的Hi大于等于与该星球直接相连的星球数(即度数)。
Source
树形DP
每个星球的Hi大于等于度数,即是说可以先遍历全图一遍并回到0点。
之后开始DP
需要用到网络流中的“退流”思想:如果相邻两点度数足够多,就可以来回走积累次数,如果这样使得之后的离开次数不够用了,就从前面退一次
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int mxn=100010; 9 int read(){ 10 int x=0,f=1;char ch=getchar(); 11 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 struct edge{ 16 int v,nxt; 17 }e[mxn<<1]; 18 int hd[mxn],mct=1; 19 void add_edge(int u,int v){ 20 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 21 } 22 int n,h[mxn],f[mxn]; 23 int smm=0; 24 int ans[mxn]; 25 void DFS(int u,int fa){ 26 for(int i=hd[u],v;i;i=e[i].nxt){ 27 v=e[i].v; 28 if(v==fa)continue; 29 DFS(v,u); 30 int tmp=min(h[v],h[u]); 31 h[v]-=tmp;h[u]-=tmp; 32 if(h[v])f[u]=v; 33 smm+=tmp<<1; 34 } 35 return; 36 } 37 int mrk[mxn]; 38 void DP(int u,int fa){ 39 ans[u]=smm; 40 for(int i=hd[u],v;i;i=e[i].nxt){ 41 v=e[i].v; 42 if(v==fa)continue; 43 if(h[u]){ 44 h[u]--;smm++; 45 DP(v,u); 46 h[u]++;smm--; 47 } 48 else if(f[v]){ 49 h[f[v]]--;smm++; 50 DP(v,u); 51 h[f[v]]++;smm--; 52 } 53 else{ 54 h[v]++;smm--; 55 DP(v,u); 56 h[v]--;smm++; 57 } 58 } 59 return; 60 } 61 int main(){ 62 int i,j,u,v; 63 n=read(); 64 for(i=1;i<=n;i++)h[i]=read(); 65 for(i=1;i<n;i++){ 66 u=read()+1;v=read()+1; 67 add_edge(u,v);add_edge(v,u); 68 --h[u];--h[v]; 69 } 70 smm=(n-1)<<1; 71 DFS(1,0); 72 DP(1,0); 73 for(i=1;i<=n;i++){ 74 printf("%d\n",ans[i]); 75 } 76 return 0; 77 }
本文为博主原创文章,转载请注明出处。