题目描述
公元30003000年,地球联盟已经攻占了银河系内的NN个星球,出于资金的考虑,政府仅仅在星球间建立了N-1N−1条双向时空隧道保证任意两个星球之间互相可达。出于管理上的考虑,第ii个星球的行政长官要求每个公民在一年内不得从该星球利用时空隧道次数超过H_iHi次(这一统计是基于离开次数统计的,如果你已经使用从该星球离开过H_iHi次,那么这一年内你就不能再使用时空隧道离开这个星球了)。Louis Paosen是一个星际旅行家,他希望能使用尽量多次的时空隧道,但又不希望最终被迫定居的星球条件太过恶劣。所以他希望能知道对于每个星球ii,若从00号星球出发,最终以ii号星球为终点,这样的星际旅行途中最多可以使用多少次时空隧道。
题解
-
首先有一个非常好的条件,每个点的限制次数都大于等于这个点的度数,然后我们可以从0开始dfs一遍这棵树。
-
然后如果一条边连接的两个点的h同时>0,那么就来回走,然后我们考虑再去从0号节点往每个节点走
-
如果此时uu的h>0,那么直接走就可以了
-
否则,那么我们为了从u走到v,必须将上一次uv折返的路程去掉,这样会使v的次数+1,这时如果v的一个儿子的次数不为0,那么还可以继续折返一次
代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 50010 5 using namespace std; 6 int head[N],cnt,h[N],ans[N],now,p[N],n; 7 struct edge{ int from,to; }e[N<<1]; 8 void insert(int u,int v){ e[++cnt].from=head[u];e[cnt].to=v;head[u]=cnt; } 9 void dfs(int u,int fa) 10 { 11 for (int i=head[u],x,v;i;i=e[i].from) 12 if (e[i].to!=fa) 13 { 14 v=e[i].to,dfs(v,u),x=min(h[u],h[v]); 15 now+=x*2,h[u]-=x,h[v]-=x; 16 if (h[v]) p[u]=v; 17 } 18 } 19 void dfs2(int u,int fa) 20 { 21 ans[u]=now; 22 for (int i=head[u];i;i=e[i].from) 23 if (e[i].to!=fa) 24 { 25 int v=e[i].to; 26 if (h[u]) h[u]--,now++,dfs2(v,u),h[u]++,now--; 27 else if (p[v]) h[p[v]]--,now++,dfs2(v,u),h[p[v]]++,now--; 28 else h[v]++,now--,dfs2(v,u),h[p[v]]--,now++; 29 } 30 } 31 int main() 32 { 33 scanf("%d",&n); 34 for (int i=1;i<=n;i++) scanf("%d",&h[i]); 35 for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),u++,v++,insert(u,v),insert(v,u),h[u]--,h[v]--,now+=2; 36 dfs(1,0),dfs2(1,0); 37 for (int i=1;i<=n;i++) printf("%d ",ans[i]); 38 }