Choosing Capital for Treeland CodeForces - 219D

原题链接

考察:树形dp

错误思路:

       换根dp,正向点权值0,逆向点权值1.求每个点到其他点的距离和.

此思路错在会多次计算要旋转的边.

思路:

        换根dp,需要两次dfs求当前结点i往下走的逆转数和往上走的逆转数.向下走的计算很容易 f[u][1]+=f[v][1]+road[i].w

        向上走如果直接推会有点难推,我们要从虚根结点出发往下推,用父节点更新子结点.(一定要从起点开始往下推啊TAT)

        f[v][0] += f[u][0]+f[u][1]-f[v][1]-road[i].w+rw

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int N = 200010;
 6 int n,f[N][2],idx,h[N];
 7 struct Road{
 8     int to,ne,w;
 9 }road[N<<1];
10 void add(int a,int b,int c)
11 {
12     road[idx].w = c,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
13 }
14 void dfs_up(int u,int fa)
15 {
16     for(int i=h[u];i!=-1;i=road[i].ne)
17     {
18         int v = road[i].to;
19         if(v==fa) continue;//向上走要连的边
20         int rw = road[i].w^1;
21         f[v][0] = f[u][1]-f[v][1]-road[i].w+rw+f[u][0];
22         dfs_up(v,u);
23     }
24 }
25 void dfs(int u,int fa)
26 {
27     for(int i=h[u];i!=-1;i=road[i].ne)
28     {
29         int v = road[i].to;
30         if(v==fa) continue;
31         dfs(v,u);
32         f[u][1] += f[v][1]+road[i].w;
33     }
34 }
35 int main()
36 {
37     while(scanf("%d",&n)!=EOF)
38     {
39         memset(h,-1,sizeof h);
40         memset(f,0,sizeof f);
41         for(int i=1;i<n;i++)
42         {
43             int a,b; scanf("%d%d",&a,&b);
44             add(a,b,0); add(b,a,1);
45         }
46         dfs(1,-1);
47         dfs_up(1,-1);
48         int ans = 1e9; 
49         for(int i=1;i<=n;i++) ans = min(ans,f[i][0]+f[i][1]);
50         printf("%d\n",ans);
51         for(int i=1;i<=n;i++)
52           if(f[i][0]+f[i][1]==ans) printf("%d ",i);
53         printf("\n");
54     }
55     return 0;
56 }

 

posted @ 2021-04-08 00:58  acmloser  阅读(37)  评论(0编辑  收藏  举报