zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Java后台获取微信小程序用户信息、openid
    异步上传excel带进度条
    iOS 手机App消息推送功能(后台Java实现)
    Java花样排序
    Java 按页拆分pdf
    Java实现按行拆分pdf
    mac 上将.pem文件转为.pub文件
    strust2的核心和工作原理
    InputStream流转字节数组
    合并InputStream流
  • 原文地址:https://www.cnblogs.com/csushl/p/10293353.html
Copyright © 2011-2022 走看看