bzoj4771 -- dfs序+倍增+主席树

Posted gjghfd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4771 -- dfs序+倍增+主席树相关的知识,希望对你有一定的参考价值。

先考虑没有深度限制的情况。

先将每个节点的权值设为1,对于颜色相同且在dfs序中最近的2个点,用倍增求出lca并将它的权值减一。然后子树中不同的颜色种数就是子树的权值和了。

有深度限制时,考虑以深度为时间建立主席树。

将每个点按深度排序,枚举一遍。对每种颜色开一个set,枚举到一个点时将它在dfs序中的位置加入set中并更新就可以了。

时间复杂度O(T*(nlogn+mlogn))

 

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    if(p1==p2){
        p2=(p1=buf)+fread(buf,1,100000,stdin);
        if(p1==p2)return EOF;
    }
    return *p1++;
}
inline void Read(int& x){
    char c=nc();
    for(;c<\'0\'||c>\'9\';c=nc());
    for(x=0;c>=\'0\'&&c<=\'9\';x=(x<<3)+(x<<1)+c-48,c=nc());
}
#define N 100010
#define M 20
#define I set<Node3>::iterator 
struct Node1{
    int w,l,r;
}a[N*M<<2];
struct Edge{
    int t,nx;
}e[N];
int x,y,Num,i,j,k,n,T,Cnt,m,d[N],Rt[N],l[N],r[N],h[N],c[N],f[N][M],Last;
struct Node3{
    int f,w;
    Node3(){}
    Node3(int f,int w):f(f),w(w){}
    bool operator < (Node3 x)const{return w<x.w;}
}A[N],Tmp;
set<Node3>s[N];
inline int _Min(int x,int y){return x<y?x:y;}
inline void Add(int x,int y){e[++Num].t=y;e[Num].nx=h[x];h[x]=Num;}
inline void Dfs(int x){
    d[x]=d[f[x][0]]+1;l[x]=++Num;
    for(int i=h[x];i;i=e[i].nx)Dfs(e[i].t);
    r[x]=Num;
}
inline void Build(int& Node,int l,int r){
    Node=++Cnt;a[Node].w=0;
    if(l==r)return;
    int Mid=l+r>>1;
    Build(a[Node].l,l,Mid);
    Build(a[Node].r,Mid+1,r);
}
inline void Insert(int L,int& Node,int x,int l,int r,int y){
    Node=++Cnt;a[Node]=a[L];
    a[Node].w+=y;
    if(l==r)return;
    int Mid=l+r>>1;
    if(x<=Mid)Insert(a[L].l,a[Node].l,x,l,Mid,y);else Insert(a[L].r,a[Node].r,x,Mid+1,r,y);
}
inline int Query(int Node,int l,int r,int L,int R){
    if(Node==0||l>R||r<L)return 0;
    if(l>=L&&r<=R)return a[Node].w;
    int Mid=l+r>>1;
    return Query(a[Node].l,l,Mid,L,R)+Query(a[Node].r,Mid+1,r,L,R);
}
inline int Lca(int x,int y){
    if(d[x]<d[y])swap(x,y);
    for(int i=M-1;i>=0;i--)
    if(d[f[x][i]]>=d[y])x=f[x][i];
    if(x==y)return x;
    for(int i=M-1;i>=0;i--)
    if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main()
{
    Read(T);
    while(T--){
        Read(n);Read(m);
        for(i=1;i<=n;i++)Read(c[i]);memset(h,0,sizeof(h));
        for(Num=Cnt=0,i=2;i<=n;i++)Read(f[i][0]),Add(f[i][0],i);
        for(j=1;j<M;j++)
        for(i=1;i<=n;i++)
        f[i][j]=f[f[i][j-1]][j-1];
        Num=0;Dfs(1);
        for(i=1;i<=n;i++)A[i].f=i,A[i].w=d[i];
        sort(A+1,A+n+1);
        for(i=1;i<=n;i++)s[i].clear();
        Build(Rt[1],1,Num);Insert(Rt[1],Rt[1],l[1],1,Num,1);s[c[1]].insert(Node3(1,l[1]));
        for(i=2;i<=n;i++){
            x=A[i-1].f;y=A[i].f;
            Insert(Rt[d[x]],Rt[d[y]],l[y],1,Num,1);
            if(s[c[y]].empty())s[c[y]].insert(Node3(y,l[y]));else{
                s[c[y]].insert(Node3(y,l[y]));
                I z=s[c[y]].find(Node3(y,l[y]));
                I P=--z;z=s[c[y]].find(Node3(y,l[y]));I S=++z;
                if(P!=s[c[y]].end())Insert(Rt[d[y]],Rt[d[y]],l[Lca(P->f,y)],1,Num,-1);
                if(S!=s[c[y]].end())Insert(Rt[d[y]],Rt[d[y]],l[Lca(S->f,y)],1,Num,-1);
                if(P!=s[c[y]].end()&&S!=s[c[y]].end())Insert(Rt[d[y]],Rt[d[y]],l[Lca(P->f,S->f)],1,Num,1);
            }
        }
        Last=0;
        while(m--){
            Read(x);Read(y);x^=Last;y^=Last;
            Last=Query(Rt[_Min(d[x]+y,A[n].w)],1,Num,l[x],r[x]);
            printf("%d\\n",Last);
        }
    }
    return 0;
}
bzoj4771

 

以上是关于bzoj4771 -- dfs序+倍增+主席树的主要内容,如果未能解决你的问题,请参考以下文章

4771: 七彩树 主席树

[BZOJ 3306]树(dfs序+线段树+倍增)

BZOJ4771七彩树 主席树+树链的并

2021牛客暑期多校训练营9E Eyjafjalla (倍增,dfs序,主席树)

bzoj3306: 树(dfs序+倍增+线段树)

BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]