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

2018-06-17 23:09:21来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

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

先将每个节点的权值设为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

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:36:二进制分类

下一篇:java中,返回1000-10000中 能被3整除,且个位数是6的个数