CSUOJ1811 Tree Intersection (启发式合并)

Bobo has a tree with n vertices numbered by 1,2,…,n and (n-1) edges. The i-th vertex has color c i, and the i-th edge connects vertices a i and b i.
Let C(x,y) denotes the set of colors in subtree rooted at vertex x deleting edge (x,y).
Bobo would like to know R_i which is the size of intersection of C(a i,b i) and C(bi,a i) for all 1≤i≤(n-1). (i.e. |C(a i,b i)∩C(b i,a i)|)

Input

The input contains at most 15 sets. For each set:
The first line contains an integer n (2≤n≤10 5).
The second line contains n integers c 1,c 2,…,c n (1≤c_i≤n).
The i-th of the last (n-1) lines contains 2 integers a i,b i (1≤a i,b i≤n).

OutputFor each set, (n-1) integers R 1,R 2,…,R n-1.Sample Input

4
1 2 2 1
1 2
2 3
3 4
5
1 1 2 1 2
1 3
2 3
3 5
4 5

Sample Output

1
2
1
1
1
2
1

Hint

 题解:题意就是,给以一颗树n个节点,每个节点有一种颜色,然年后对于n-1条边,如果把一条边截断,让你求两颗子树有多少种相同的颜色,依次输入每一条边的答案。

启发式搜索,分别记录点和边的答案;如果点u和其子树某种颜色的数量已经等于总量了,那么对于该子树外的一部分,就没有该中颜色了,答案-1;如果小于总量,答案+1;

然后更新u节点该颜色的数量即可;

参考代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define clr(a,val) memset(a,val,sizeof (a))
 4 #define pb push_back
 5 #define fi first
 6 #define se second
 7 typedef long long ll;
 8 const int maxn=1e5+10;
 9 inline int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 struct Edge{
17     int to,index,nxt;
18 } edge[maxn<<1];
19 int n,head[maxn<<1],tot;
20 int col[maxn],sum[maxn],ans[maxn],res[maxn<<1];//ans[u]表示u点及子节点的答案, res[edge]表示边的答案
21 map<int,int> cnt[maxn];//cnt[u][color] 表示u点子树color颜色有多少个节点
22 
23 inline void Init()
24 {
25     clr(head,-1);clr(sum,0); tot=0;
26     for(int i=0;i<=n;++i) cnt[i].clear();
27 }
28 
29 inline void addedge(int u,int v,int id)
30 {
31     edge[tot].to=v;
32     edge[tot].index=id;
33     edge[tot].nxt=head[u];
34     head[u]=tot++;
35 }
36 
37 inline void dfs(int u,int fa,int id)
38 {
39     cnt[u][col[u]]=1;
40     ans[u] = cnt[u][col[u]]<sum[col[u]]?1:0;
41     for(int e=head[u];~e;e=edge[e].nxt)
42     {
43         int v=edge[e].to;
44         if(v==fa) continue;
45         dfs(v,u,edge[e].index);
46         if(cnt[u].size()<cnt[v].size())
47         {
48             swap(cnt[u],cnt[v]);
49             swap(ans[u],ans[v]);
50         }
51         map<int,int>::iterator it;
52         for(it=cnt[v].begin();it!=cnt[v].end();it++)
53         {
54             if(!cnt[u][(*it).fi] && (*it).se<sum[(*it).fi]) ++ans[u];
55             else if(cnt[u][(*it).fi] && cnt[u][(*it).fi]+(*it).se==sum[(*it).fi]) --ans[u];
56             cnt[u][(*it).fi]+=(*it).se;//加上子树的数量 
57         }
58     }
59     res[id]=ans[u];
60 }
61 
62 int main()
63 {
64     while(~scanf("%d",&n))
65     {
66         Init();
67         for(int i=1;i<=n;++i) col[i]=read(),sum[col[i]]++;
68         for(int i=1;i<n;++i) 
69         {
70             int u=read(),v=read();
71             addedge(u,v,i);addedge(v,u,i);
72         }
73         dfs(1,0,0);
74         for(int i=1;i<n;++i) printf("%d
",res[i]);    
75     }
76     
77     return 0;
78 }
View Code
原文地址:https://www.cnblogs.com/csushl/p/10293353.html