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\n",res[i]); 75 } 76 77 return 0; 78 }