http://codeforces.com/problemset/problem/763/A Timofey and a tree

给定一颗树且其结点有颜色,问是否存在一个节点以它为一个割点,分割出来的其他子树颜色相同。
有一丝启发式合并的韵味。首先很容易想到枚举每一个结点去判断它是否是满足条件的一个点。
但这样判断其分割得到的子树是否颜色相同时间复杂度会为O(n^2),首先考虑枚举一个点,求得的信息
和枚举其他点的信息是否存在重复,很容易想到去考虑一个结点和其根结点所要求的信息之间的关系,
如果把结点u作为割点,则必须得到1.子节点为根的子树颜色相同,父节点为根的子树颜色相同(且不包含u
结点的子树) 但如果把u节点的一个子节点v作为割点,则和上述的要求相同,这里可以看出这实际上是同类
型的问题,那么如果以u为根的子树不符合条件,且v为根的子树不符合条件,显然v的子树必定会影响到u,
那么,要使得u为根的子树符合条件,实际上就可能是去把v为根的子树中的某个结点作为割点,这显然是作为
一种启发,另外合并的操作在于合并u的信息和其他儿子的信息,具体的判断 不再阐述,看代码即可。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cmath>
#include <vector>
#define MAX 100005
#define INF 0x3f3f3f3f
using namespace std;
int n,c[MAX],x,y,d[MAX],ans;
vector<int> G[MAX];
bool vis[MAX];
void dfs1(int v){//d[v]表示以v为根节点的子树的相同颜色,若有不同的其值为-1
    vis[v] = true;
    d[v] = c[v];
    bool f = false;
    for(int i = 0;i < G[v].size();++i){
        int t = G[v][i];
        if(!vis[t]){
            dfs1(t);
            f = true;
            if(d[v] != d[t]) d[v] = -1;
        }
    }
    vis[v] = false;
}
bool dfs2(int v,int pre){
    vis[v] = true;
    if(d[v] == -1){//1.存在子节点d[v] = -1 ! 2.存在两个子节点d[v] != d[u]
        int counter = 0,u = -1;
        for(int i = 0;i < G[v].size();++i){
            int t = G[v][i];
            if(vis[t]) continue;
            if(d[t] == -1) counter++,u = t;
        }
        if(counter >= 2) return false;
        //c <= 1
        if(counter == 0) {ans = v;return true;}
        else{ // c = 1
            if(d[pre] != c[v]) return false;
            for(int i = 0;i < G[v].size();++i){
                int t = G[v][i];
                if(vis[t] || t == u) continue;
                if(d[t] != c[v]) return false;
            }
            d[v] = c[v];
            return dfs2(u,v);
        }
    }
    ans = v;
    return true;
}
int main()
{
    cin >> n;
    for(int i = 1;i < n;++i){
        scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    for(int i = 1;i <= n;++i){
        scanf("%d",&c[i]);
    }
    dfs1(1);
    d[0] = c[1];
    ans = -1;
    if(dfs2(1,0)) cout << "YES" << endl << ans << endl;
    else cout << "NO" << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值