1811: Tree Intersection

1811: Tree Intersection

Submit Page      Summary      Time Limit: 5 Sec       Memory Limit: 128 Mb       Submitted: 392       Solved: 158    

Description

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 iand 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(b i,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).

Output

For 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


方法一:线段树合并。

#include"cstdio"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"vector"
using namespace std;
const int maxn = 1e5+5;
const int maxm = 3e6+5;
int n,col[maxn],c[maxn],ans[maxn],r[maxn];
struct edge{
    int v,nxt;
}e[maxn<<1];
int alloc,tail,head[maxn];
void init(){
    alloc = 0;
    tail = -1;
    memset(head,-1,sizeof(head));
    memset(col,0,sizeof(col));
}
void add(int u, int v)
{
    e[++tail] = (edge){v,head[u]}; head[u] = tail;
    e[++tail] = (edge){u,head[v]}; head[v] = tail;
}

struct node{
    int l,r;
    int val,sum;
}tree[maxm];

void pushup(int rt)
{
    tree[rt].sum = tree[tree[rt].l].sum + tree[tree[rt].r].sum;
}

int build(int c, int l, int r)
{
    int rt = ++alloc;
    tree[rt].l = tree[rt].r = 0;
    tree[rt].val = tree[rt].sum = 0;
    if(l == r){
        tree[rt].val = 1;
        tree[rt].sum = (tree[rt].val < col[l]);
        return rt;
    }
    int mid = l+r>>1;
    if(c <= mid) tree[rt].l = build(c,l,mid);
    else tree[rt].r = build(c,mid+1,r);
    pushup(rt);
    return rt;
}

int merge(int rt1, int rt2, int l, int r)
{
    if(!rt1) return rt2;
    if(!rt2) return rt1;
    if(l == r){
        tree[rt1].val += tree[rt2].val;
        tree[rt1].sum = (tree[rt1].val < col[l]);
        return rt1;
    }
    int mid = l+r>>1;
    tree[rt1].l = merge(tree[rt1].l,tree[rt2].l,l,mid);
    tree[rt1].r = merge(tree[rt1].r,tree[rt2].r,mid+1,r);
    pushup(rt1);
    return rt1;
}

void dfs(int u, int fa, int ed)
{
    r[u] = build(c[u],1,n);
    for(int i = head[u]; ~i; i = e[i].nxt){
        int v = e[i].v;
        if(v == fa) continue;
        dfs(v,u,i);
        merge(r[u],r[v],1,n);
    }
//    cout<
    ans[ed/2+1] = tree[r[u]].sum;
}

int main()
{
    int u,v;
    while(~scanf("%d",&n)){
        init();
        for(int i = 1; i <= n; i++){
            scanf("%d",&c[i]);
            col[c[i]]++;
        }
        for(int i = 1; i < n; i++){
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        dfs(1,1,-2);
        for(int i = 1; i < n; i++){
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}
方法二:dfs序+莫队算法

#include"cmath"
#include"cstdio"
#include"cstring"
#include"iostream"
#include"vector"
#include"algorithm"
using namespace std;
const int maxn = 1e5+7;
int ans[maxn],a[maxn],b[maxn],col[maxn],cnt[maxn],fro[maxn],head[maxn],flag[maxn];
int pos[maxn];
int n,tot,ed,tail;

struct edge{
    int to, nxt;
}e[maxn*2];

struct node{
    int l, r, id;
    node(){}
    node(int ll, int rr, int ii):l(ll),r(rr),id(ii){}
}Q[maxn];

void add(int u, int v)
{
    e[++ed] = (edge){v,head[u]}; head[u] = ed;
    e[++ed] = (edge){u,head[v]}; head[v] = ed;
}
void dfs(int u, int fa, int edg)
{
    fro[u] = ++tot;
    a[tot] = b[u];
    for(int i = head[u]; i; i = e[i].nxt){
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v,u,i);
    }
    Q[++tail] = node(fro[u],tot,(edg+1)/2);
}

bool cmp(node a, node b){
    if(pos[a.l] == pos[b.l])
        return a.r < b.r;
    return pos[a.l] < pos[b.l];
}

void work(int id, int &now)
{
    if(cnt[id] > 0 && cnt[id] < col[id]){
        if(!flag[id]) now++;
        flag[id] = 1;
    }
    else{
        if(flag[id]) now--;
        flag[id] = 0;
    }
}
int main()
{
    int u,v;
    while(~scanf("%d",&n)){
        int sz = sqrt(n);
        tot = ed = tail = 0;
        memset(col,0,sizeof(col));
        memset(cnt,0,sizeof(cnt));
        memset(head,0,sizeof(head));
        memset(flag,0,sizeof(flag));
        for(int i = 1; i <= n; i++){
            int x;
            scanf("%d",&x);
            b[i] = x;
            col[x]++;
            pos[i] = i/sz;
        }
        for(int i = 1; i < n; i++){
           scanf("%d%d",&u,&v);
           add(u,v);
        }
        dfs(1,1,0);
        sort(Q+1,Q+n,cmp);
        int L = 1, R = 0, now = 0;
        for(int i = 1; i < n; i++){
            while(L < Q[i].l){
                L++;
                int id = a[L-1];
                cnt[id]--;
                work(id,now);
            }
            while(L > Q[i].l){
                int id = a[L-1];
                cnt[id]++;
                L--;
                work(id,now);
            }
            while(R < Q[i].r){
                R++;
                int id = a[R];
                cnt[id]++;
                work(id,now);
            }
            while(R > Q[i].r){
                int id = a[R];
                cnt[id]--;
                R--;
                work(id,now);
            }

            ans[Q[i].id] = now;
        }
        for(int i = 1; i < n; i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}




你可能感兴趣的:(1811: Tree Intersection)