题目链接:http://codeforces.com/contest/1118/problem/F1
题目大意:有一棵树,有的节点是红色,有的节点是蓝色,有的节点没有颜色。把一条边拆开,分成两棵树,如果这两棵树都没有同时拥有两种颜色的节点那么这条边就是“漂亮的边”。问有多少这样的边。


思路:以dfs的顺序维护dp[i][0], dp[i][1]。分别表示以节点i为子树的红色节点数,和以节点i为子树的蓝色节点数。

dp[i][0]=节点i所有的子树的红色个数+(a[i]==1?1:0)/*自身的颜色*/

节点i所有的子树:dfs的顺序就是自己子树的根节点。
所以:dp[i][0]=(dp[i][j])+(a[i]==1?1:0)节点i到节点j有边相连。
并且节点j不是来到节点i的那个节点。那是节点i的父节点。

void dfs(int k)
{
    vis[k]=1;
    if(f[k]==1)        //初始化自身节点颜色
    {
        dp[k][0]++;
    }
    if(f[k]==2)
    {
        dp[k][1]++;
    }

    for(int i=e[k].size()-1;i>=0;i--)
    {
        int to=e[k][i];
        if(!vis[to])
        {
            dfs(to);
            dp[k][0]+=dp[to][0];//所有子节点的颜色
            dp[k][1]+=dp[to][1];
        }
    }
}

此时对于一条边,以dfs的顺序判断它的任意子树上的红色与蓝色的节点数。与另外一棵树的红色与蓝色的节点数。是否满足条件。
对于子树上的红色与蓝色的节点数就是dp[i][0], dp[i][1]。而另外一棵树可以用总的红色节点数-dp[i][0],总的 蓝色的节点数-dp[i][1]计算。

int  ans=0;
void DFS(int k)
{
    vis[k]=1;
    if(dp[k][0]==A&&dp[k][1]==0)//如果子树拥有全部红色节点
    {
        ans++;
    }
    else if(dp[k][1]==B&&dp[k][0]==0)//如果子树拥有全部蓝色节点
    {
        ans++;
    }
    for(int i=e[k].size()-1;i>=0;i--)
    {
        int to=e[k][i];
        if(!vis[to])
        {
            DFS(to);
        }
    }
}

思考:经典的维护子树信息的题。

全部代码:

#include<bits/stdc++.h>
#define LL long long
//#define p1 first
//#define p2 second
using namespace std;
const int mod=1e9+7;
//memset(a, 0, sizeof(a));
//next(p, 1), prev(p, 1), set<int>::iterator
//stack堆栈 queue队列 priority_queue优先队列
//vector向量 multiset平衡二叉树 deque双端队列
//pair{T1 first;T2 second;} greater<T>
//unordered_map 哈希map

vector<int> e[300005]; //存图
int f[300005];         //保存节点的颜色
int A, B;              //整棵树的红色与蓝色节点总和
int dp[300005][2]={0}; //以i节点为根节点的红色与蓝色节点数

int vis[300005]={0};
void dfs(int k)
{
    vis[k]=1;
    if(f[k]==1)        //初始化自身节点颜色
    {
        dp[k][0]++;
    }
    if(f[k]==2)
    {
        dp[k][1]++;
    }

    for(int i=e[k].size()-1;i>=0;i--)
    {
        int to=e[k][i];
        if(!vis[to])
        {
            dfs(to);
            dp[k][0]+=dp[to][0];//所有节点的颜色
            dp[k][1]+=dp[to][1];
        }
    }
}

int  ans=0;
void DFS(int k)
{
    vis[k]=1;
    if(dp[k][0]==A&&dp[k][1]==0)//如果子树拥有全部红色节点
    {
        ans++;
    }
    else if(dp[k][1]==B&&dp[k][0]==0)//如果子树拥有全部蓝色节点
    {
        ans++;
    }
    for(int i=e[k].size()-1;i>=0;i--)
    {
        int to=e[k][i];
        if(!vis[to])
        {
            DFS(to);
        }
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&f[i]);
    }
    for(int i=0;i<n-1;i++)
    {
        int x, y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    A=count(f+1, f+1+n, 1);
    B=count(f+1, f+1+n, 2);
    dfs(1);
    memset(vis, 0, sizeof(vis));
    DFS(1);
    cout<<ans<<endl;

    return 0;
}

#include<bits/stdc++.h>
#define LL long long
//#define p1 first
//#define p2 second
using namespace std;
const int mod=1e9+7;
//memset(a, 0, sizeof(a));
//next(p, 1), prev(p, 1), set<int>::iterator
//stack堆栈 queue队列 priority_queue优先队列
//vector向量 multiset平衡二叉树 deque双端队列
//pair{T1 first;T2 second;} greater<T>
//unordered_map 哈希map

vector<int> e[300005]; //存图
int f[300005];         //保存节点的颜色
int A, B;              //整棵树的红色与蓝色节点总和
int dp[300005][2]={0}; //以i节点为根节点的红色与蓝色节点数

int vis[300005]={0};
void dfs(int k)
{
    vis[k]=1;
    if(f[k]==1)        //初始化自身节点颜色
    {
        dp[k][0]++;
    }
    if(f[k]==2)
    {
        dp[k][1]++;
    }

    for(int i=e[k].size()-1;i>=0;i--)
    {
        int to=e[k][i];
        if(!vis[to])
        {
            dfs(to);
            dp[k][0]+=dp[to][0];//所有节点的颜色
            dp[k][1]+=dp[to][1];
        }
    }
}

int DFS(int n)
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(dp[i][0]==A&&dp[i][1]==0)     //如果子树拥有全部红色节点
        {
            ans++;
        }
        else if(dp[i][1]==B&&dp[i][0]==0)//如果子树拥有全部蓝色节点
        {
            ans++;
        }
    }

    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&f[i]);
    }
    for(int i=0;i<n-1;i++)
    {
        int x, y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    A=count(f+1, f+1+n, 1);
    B=count(f+1, f+1+n, 2);
    dfs(1);
    memset(vis, 0, sizeof(vis));
    cout<<DFS(n)<<endl;

    return 0;
}