[bzoj4771]七彩树

题目描述

给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节
点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离
,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。
每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色
。请写一个程序,快速回答这些询问。

口胡里说了。
不考虑深度,把同颜色的点按dfn排序,每个点对应位置+1,两两相邻lca处-1。这显然是是对的。
考虑深度,我们可以按深度排序依次插入,建可持久化线段树,查询直接查。
加速代码可以考虑询问时访问到空节点就直接退出。

#include
#include
#include
#include
#define min(a,b) (a
#define max(a,b) (a>b?a:b)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,maxtot=14000000+10;
int dfn[maxn],b[maxn],c[maxn],h[maxn],go[maxn],next[maxn],size[maxn];
int f[maxn][20],d[maxn],zjy[maxn];
int tree[maxtot],left[maxtot],right[maxtot],root[maxn],sta[80];
int i,j,k,l,r,x,y,t,n,m,mx,top,tot,ans,ca;
bool czy;
struct set_cmp{
    bool operator ()(const int &x,const int &y){
        return dfn[x]multiset<int,set_cmp> s[maxn];
multiset<int,set_cmp>::iterator it;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void add(int x,int y){
    go[++tot]=y;
    next[tot]=h[x];
    h[x]=tot;
}
void dfs(int x){
    dfn[x]=++top;
    size[x]=1;
    int t=h[x];
    while (t){
        f[go[t]][0]=x;
        d[go[t]]=d[x]+1;
        dfs(go[t]);
        size[x]+=size[go[t]];
        t=next[t];
    }
}
bool cmp(int x,int y){
    return d[x]int lca(int x,int y){
    if (d[x]if (d[x]!=d[y]){
        int j=zjy[d[x]-d[y]];
        while (j>=0){
            if (d[f[x][j]]>=d[y]) x=f[x][j];
            j--;
        }
    }
    if (x==y) return x;
    int j=zjy[d[x]];
    while (j>=0){
        if (f[x][j]!=f[y][j]){
            x=f[x][j];
            y=f[y][j];
        }
        j--;
    }
    return f[x][0];
}
int newnode(int x){
    tot++;
    tree[tot]=tree[x];
    left[tot]=left[x];
    right[tot]=right[x];
    return tot;
}
void insert(int &x,int l,int r,int a,int b){
    x=newnode(x);
    if (l==r){
        tree[x]+=b;
        return;
    }
    int mid=(l+r)/2;
    if (a<=mid) insert(left[x],l,mid,a,b);else insert(right[x],mid+1,r,a,b);
    tree[x]=tree[left[x]]+tree[right[x]];
}
int query(int x,int l,int r,int a,int b){
    if (!x) return 0;
    if (l==a&&r==b) return tree[x];
    int mid=(l+r)/2;
    if (b<=mid) return query(left[x],l,mid,a,b);
    else if (a>mid) return query(right[x],mid+1,r,a,b);
    else return query(left[x],l,mid,a,mid)+query(right[x],mid+1,r,mid+1,b);
}
void write(int x){
    if (!x){
        putchar('0');
        putchar('\n');
        return;
    }
    top=0;
    while (x){
        sta[++top]=x%10;
        x/=10;
    }
    while (top) putchar('0'+sta[top--]);
    putchar('\n');
}
int main(){
    freopen("paint.in","r",stdin);freopen("data.out","w",stdout);
    //czy=1;
    ca=read();
    //ca=1;
    while (ca--){
    n=read();m=read();
    fo(i,1,n) c[i]=read();
    fo(i,1,n) s[i].clear();
    fo(i,1,n) h[i]=0;
    tot=0;
    fo(i,2,n){
        j=read();
        add(j,i);
    }
    d[1]=1;
    top=0;
    dfs(1);
    fo(i,1,n) zjy[i]=floor(log(i)/log(2));
    fo(j,1,zjy[n])
        fo(i,1,n)
            f[i][j]=f[f[i][j-1]][j-1];
    fo(i,1,n) b[i]=i;
    sort(b+1,b+n+1,cmp);
    mx=0;
    fo(i,1,n) mx=max(mx,d[i]);
    j=k=tot=0;
    fo(l,1,mx){
        j=k+1;
        while (k1]]==l) k++;
        root[l]=root[l-1];
        fo(i,j,k){
            t=b[i];
            insert(root[l],1,n,dfn[t],1);
            it=s[c[t]].lower_bound(t);
            if (it==s[c[t]].end()&&it==s[c[t]].begin()){
                s[c[t]].insert(t);
                continue;
            }
            else if (it==s[c[t]].end()){
                x=*(--it);
                insert(root[l],1,n,dfn[lca(t,x)],-1);
            }
            else if (it==s[c[t]].begin()){
                y=*it;
                insert(root[l],1,n,dfn[lca(t,y)],-1);
            }
            else{
                y=*it;
                x=*(--it);
                insert(root[l],1,n,dfn[lca(x,y)],1);
                insert(root[l],1,n,dfn[lca(t,x)],-1);
                insert(root[l],1,n,dfn[lca(t,y)],-1);
            }
            s[c[t]].insert(t);
        }
    }
    ans=0;
    fo(i,1,m){
        x=read();y=read();
        if (czy){
            x^=ans;
            y^=ans;
        }
        ans=query(root[min(d[x]+y,mx)],1,n,dfn[x],dfn[x]+size[x]-1);
        write(ans);
    }
    }
}

你可能感兴趣的:(可持久化线段树)