BZOJ4771 七彩树(主席树)

一道主席树好题

对于每种颜色来说,将同种颜色的节点按照 dfn 排序,每个点的贡献是1,相邻两个点对 LCA 的贡献-1,

只要区间内存在这种颜色,则其子树内的权值和必定为1。染好所有颜色之后询问子树和。  (不知道为什么)

按照深度建立主席树,询问就是区间查询啦

(不知道为什么主席树要开<<7的空间啊,因为这个一直RE。。)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int n,m,q,f,x,d,test;
int c[maxn],b[maxn],p[maxn];

set<int> S[maxn]; set<int>::iterator t1,t2,t3;

int h[maxn],size;
struct E{
    int to,next;
}e[maxn*2];
void add(int u,int v){
    e[++size].to=v;
    e[size].next=h[u];
    h[u]=size;
} 

int rt[maxn];
int lc[maxn<<7],rc[maxn<<7],val[maxn<<7],cnt;
void modify(int &i,int o,int l,int r,int p,int v){
    i=++cnt;
    lc[i]=lc[o],rc[i]=rc[o],val[i]=val[o]+v;
    if(l==r) return;
    int mid=(l+r)/2;
    if(p<=mid) modify(lc[i],lc[i],l,mid,p,v);
    else modify(rc[i],rc[i],mid+1,r,p,v);
}

int query(int i,int l,int r,int x,int y){
    if(x<=l && r<=y) return val[i];
    int mid=(l+r)/2,res=0;
    if(x<=mid) res+=query(lc[i],l,mid,x,y);
    if(y>mid) res+=query(rc[i],mid+1,r,x,y);
    return res;
}

int dep[maxn],fa[maxn],son[maxn],top[maxn],sz[maxn],dfn[maxn],low[maxn],id[maxn],tot;

void dfs1(int u,int par){
    sz[u]=1; int maxs=-1;
    son[u]=0;
    fa[u]=par;
    dep[u]=dep[par]+1;
    
    for(int i=h[u];i!=-1;i=e[i].next){
        int v=e[i].to;
        if(v==par) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>maxs){
            maxs=sz[v];
            son[u]=v;
        }
    }
}

void dfs2(int u,int par){
    dfn[u]=++tot;
    top[u]=par;
    id[tot]=u;
    
    if(!son[u]){
        low[u]=tot; 
        return;
    }
    dfs2(son[u],par);
    for(int i=h[u];i!=-1;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u] || v==son[u]) continue;
        dfs2(v,v);
    }
    low[u]=tot;
}

int LCA(int u,int v){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    return u;
}

bool cmp(int a,int b){ return dep[a]<dep[b]; }

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
    test=read();
    while(test--){
    memset(h,-1,sizeof(h));
    cnt=0,tot=0,size=0;
    memset(rt,0,sizeof(rt));
    memset(dfn,0,sizeof(dfn)); memset(id,0,sizeof(id));
     
    n=read(),m=read();
    
    for(int i=1;i<=n;i++) c[i]=read(),b[i]=c[i];
    sort(b+1,b+1+n);
    q=unique(b+1,b+1+n)-b-1;
    
    for(int i=1;i<=n;i++) c[i]=lower_bound(b+1,b+1+q,c[i])-b;
    
    for(int i=2;i<=n;i++) f=read(),add(f,i),add(i,f);
    dfs1(1,0); dfs2(1,1);
    
    for(int i=1;i<=n;i++) p[i]=i;
    sort(p+1,p+1+n,cmp);
    
    for(int i=1;i<=q;i++) S[i].clear();
    
    for(int i=1,j=1;i<=dep[p[n]];i++){
        rt[i]=rt[i-1];
        while(j<=n && dep[p[j]]==i){
            int u=p[j];
            S[c[u]].insert(dfn[u]);
            t1=t2=t3=S[c[u]].find(dfn[u]);
            t2--,t3++;
            modify(rt[i],rt[i],1,n,dfn[u],1);
            if(t1!=S[c[u]].begin()) modify(rt[i],rt[i],1,n,dfn[LCA(u,id[*t2])],-1);                      // 
            if(t3!=S[c[u]].end()) modify(rt[i],rt[i],1,n,dfn[LCA(u,id[*t3])],-1);                         // 
            if(t1!=S[c[u]].begin() && t3!=S[c[u]].end()) modify(rt[i],rt[i],1,n,dfn[LCA(id[*t2],id[*t3])],1);  // 重点  
            ++j;
        }
    }
    
    int ans=0; 
    for(int i=1;i<=m;i++){
        x=read()^ans,d=read()^ans;
        ans=query(rt[min(dep[x]+d,dep[p[n]])],1,n,dfn[x],low[x]);
        printf("%d\n",ans);
    }
}
    return 0;
}

 

  

上一篇:第十三篇 -- 学习第十二天打卡20190630


下一篇:[bzoj3223]文艺平衡树(splay区间反转模板)