Coloring Tree

给你一棵N个节点的树(无向无环连通图),每个节点有一个颜色。你知道树的根节点(树的根节点是一个特殊的节点,是树节点中唯一没有父节点的)。颜色用1到109范围内的整数表示。现在,你需要回答M个查询,每个查询询问以节点s为根的子树节点中,不同颜色的数目。(s会在输入中给出)。

输入格式

第一行包含3个空格分隔的整数 (N M root)表示树的节点数、查询数和根节点。

接下来N行,每行包含着2个空格分隔的整数(a b)表示一条从节点a到节点b的边。

接下来N行, 第i行表示第i个节点的颜色。

接下来M行,每行包含一个整数s。

输出格式

输出M行,每行输出对应查询的结果。

约束条件

0=< M <= 105
1=< N <= 105
1=< root <= N
1=< 节点颜色 <= 109

样例

输入样例

4 2 1
1 2
2 4
2 3
10
20
20
30
1
2
输出样例

3
2
解释

查询1 以1为根的子树就是整个树,包含颜色10 20 20 30, 所以结果是3(10,20 and 30)。

查询2 以2为节点的子树包含颜色20 20 30, 所以答案是2(20 and 30)。

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100010;

struct Edge {
    int v, next;
    Edge() { }
    Edge(int _v, int _next) : v(_v), next(_next) { }
}edges[2*maxn];
int head[maxn], edge_num;
int color[maxn], ans[maxn], id[maxn];
set<int> ver[maxn];
int n, m, r;

void init_graph() {
    edge_num = 0;
    memset(head, -1, sizeof(head));
}

void add_edge(int u, int v) {
    edges[edge_num].v = v;
    edges[edge_num].next = head[u];
    head[u] = edge_num++;

    edges[edge_num].v = u;
    edges[edge_num].next = head[v];
    head[v] = edge_num++;
}

void merge(int &u, int &v) {
    if(ver[u].size() < ver[v].size()) swap(u, v);
    for(set<int>::iterator it = ver[v].begin(); it != ver[v].end(); ++it) {
        ver[u].insert(*it);
    }
    return ;
}

void dfs(int u, int f) {
    ver[id[u]].insert(color[u]);
    for(int i = head[u]; i != -1; i = edges[i].next) {
        int v = edges[i].v;
        if(v == f) continue;
        dfs(v, u);
        merge(id[u], id[v]);    
    }
    ans[u] = ver[id[u]].size();
    return ;
}


int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */   
    int u, v;
    init_graph();
    scanf("%d %d %d", &n, &m, &r);
    for(int i = 1; i < n; ++i) {
        scanf("%d %d", &u, &v);
        add_edge(u, v);
    }
    for(int i = 1; i <= n; ++i) {
        id[i] = i;
        scanf("%d", &color[i]);
    }
    dfs(r, -1);
    for(int i = 0; i < m; ++i) {
        scanf("%d", &u);
        printf("%d\n", ans[u]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值