标签:隧道 次数 Luogu dfs ii P4189 时空 include 星球
题目描述
公元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\n",ans[i]); 38 }
标签:隧道,次数,Luogu,dfs,ii,P4189,时空,include,星球 来源: https://www.cnblogs.com/Comfortable/p/11237274.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。