标签:
题意:
给你一个有向树,求以每个节点为根,可到达其他任何一个节点需要反向的边数。
分析:数据规模大,若一个节点一个节点的算,必超时,有了上一道题的积累,这个题的状态就好想了,当前节点需要的翻边的数量,由子树得的加上由父节点过来的数量。两次dfs
#include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <string> #include <cctype> #include <complex> #include <cassert> #include <utility> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; typedef pair<int,int> PII; typedef long long ll; #define lson l,m,rt<<1 #define pi acos(-1.0) #define rson m+1,r,rt<<11 #define All 1,N,1 #define read freopen("in.txt", "r", stdin) #define N 200100 const ll INFll = 0x3f3f3f3f3f3f3f3fLL; const int INF= 0x7ffffff; const int mod = 1000000007; struct tree{ int u,v,next,num; }t[2*N]; //dp[i]以i为根由子树得的数量 //dp1[i]以i为根由父节点得的数量 int dp[N],dp1[N],head[2*N],used[N],len,city[N],n; void add(int a,int b,int c){ t[len].u=a; t[len].v=b; t[len].num=c; t[len].next=head[a]; head[a]=len++; } void dfs(int root){ used[root]=1; for(int i=head[root];i!=-1;i=t[i].next){ int son=t[i].v; if(used[son])continue; dfs(son); dp[root]+=dp[son]+t[i].num; } } void dfs1(int root){ used[root]=1; for(int i=head[root];i!=-1;i=t[i].next){ int son=t[i].v; if(used[son])continue; dp1[son]=dp1[root]+(t[i].num?0:1)+dp[root]-dp[son]-t[i].num; dfs1(son); } } int main() { while(~scanf("%d",&n)){ memset(head,-1,sizeof(head)); len=0; int a,b; for(int i=0;i<n-1;++i){ scanf("%d%d",&a,&b); add(a,b,0);// 不用反向权值为0 add(b,a,1);//要反向权值为1 } int l,minn=INF; memset(used,0,sizeof(used)); memset(dp,0,sizeof(dp)); dfs(1); memset(used,0,sizeof(used)); memset(dp1,0,sizeof(dp1)); dfs1(1); for(int i=1;i<=n;++i){ if(dp[i]+dp1[i]<minn){ l=0; city[l++]=i; minn=dp[i]+dp1[i]; } else if(dp[i]+dp1[i]==minn){ city[l++]=i; } } printf("%d\n",minn); for(int i=0;i<l;++i) printf("%d ",city[i]); printf("\n"); } return 0; }
CodeForces 219D-Choosing Capital for Treeland
标签:
原文地址:http://www.cnblogs.com/zsf123/p/4697316.html