[BZOJ4771]七彩树(主席树+STL)

题目:

我是超链接

题解:

说起来颜色相同不同,有点像之前做过的AC自动机的题目【喵星人】
因为是用了树上容斥的方法,首先考虑没有深度限制的情况
先令每个点的贡献都是1,那么如果有同色点,他们的lca的贡献就-1,所以令同色点dfs序相邻的点贡献-1,然后答案就是子树和
考虑深度限制,我们搞个主席树,然后把深度为i的点挨个插进来即可(一次插进来一层),插的时候用set维护一下每个颜色的dfs序,每次加入一个点,点值+1,与前驱的lca-1,与后缀的lca-1,前驱与后缀的lca+1。然后查询的时候查询子树区间就好
然后i2写成i1调了两节课= =

代码:

#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=200005;
const int sz=31;
vector <int> dep[N];
int tot,nxt[N*2],point[N],v[N*2],c[N],mi[sz+5],f[N][sz+5],deep,dfn[N],h[N],out[N],nn,size,root[N];
struct hh{int l,r,w;}tree[N*60];
struct cmp
{
    bool operator()(const int x,const int y)
    {
        return dfn[x]<dfn[y];
    }
};
set<int,cmp>s[N];
void addline(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int fa)
{
    h[x]=h[fa]+1; dfn[x]=++nn; dep[h[x]].push_back(x); deep=max(deep,h[x]);
    for (int i=1;i<sz;i++)
      if (h[x]<mi[i]) break;
      else f[x][i]=f[f[x][i-1]][i-1];
    for (int i=point[x];i;i=nxt[i])
      if (v[i]!=fa) f[v[i]][0]=x,dfs(v[i],x); 
    out[x]=nn;
}
int lca(int x,int y)
{
    if (h[x]<h[y]) swap(x,y);
    int k=h[x]-h[y];
    for (int i=0;i<sz;i++)
      if (k>>i&1) x=f[x][i];
    if (x==y) return x;
    for (int i=sz-1;i>=0;i--)
      if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int insert(int now,int l,int r,int x,int v)
{
    if (!now)
    {
        now=++size;
        tree[now].l=tree[now].r=tree[now].w=0;
    }
    tree[now].w+=v;
    if (l==r) return now;
    int mid=(l+r)>>1;
    if (x<=mid) tree[now].l=insert(tree[now].l,l,mid,x,v);
    else tree[now].r=insert(tree[now].r,mid+1,r,x,v);
    return now;
}
int merge(int i,int j,int l,int r)
{
    if (i==0 || j==0) return i+j; 
    tree[i].w+=tree[j].w;
    if (l==r) return i;
    int mid=(l+r)>>1; 
    tree[i].l=merge(tree[i].l,tree[j].l,l,mid);
    tree[i].r=merge(tree[i].r,tree[j].r,mid+1,r);
    return i;
}
void clear()
{
    memset(point,0,sizeof(point));
    tot=0;deep=0;nn=0;size=0;
}
int qurry(int i,int l,int r,int lrange,int rrange)
{
    if (!i) return 0;
    if (lrange<=l && rrange>=r) return tree[i].w;
    int mid=(l+r)>>1,ans=0;
    if (lrange<=mid) ans+=qurry(tree[i].l,l,mid,lrange,rrange);
    if (rrange>mid) ans+=qurry(tree[i].r,mid+1,r,lrange,rrange);
    return ans;
}
int main()
{
    mi[0]=1;for (int i=1;i<sz;i++) mi[i]=mi[i-1]*2;
    int T,n,m,id=0;scanf("%d",&T);
    while (T--)
    {
        clear();
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) dep[i].clear(),s[i].clear(),memset(f[i],0,sizeof(f[i]));
        for (int i=1;i<=n;i++) scanf("%d",&c[i]);
        for (int i=2;i<=n;i++)
        {
            int x;scanf("%d",&x);
            addline(x,i);
        }
        dfs(1,0); root[0]=0;
        for (int i=1;i<=deep;i++)
        {
            root[i]=0;
            for (int j=0;j<dep[i].size();j++) 
            {
                int x=dep[i][j];
                root[i]=insert(root[i],1,n,dfn[x],1);
                set<int>::iterator i1,i2;
                i1=s[c[x]].lower_bound(x);
                int pre= i1==s[c[x]].begin()?-1:*(--i1);

                i2=s[c[x]].lower_bound(x);
                int nxt= i2==s[c[x]].end()?-1:*i2;
                if (pre!=-1) root[i]=insert(root[i],1,n,dfn[lca(pre,x)],-1);
                if (nxt!=-1) root[i]=insert(root[i],1,n,dfn[lca(nxt,x)],-1);
                if (pre!=-1 && nxt!=-1) root[i]=insert(root[i],1,n,dfn[lca(pre,nxt)],1);
                s[c[x]].insert(x);
            }  
            root[i]=merge(root[i],root[i-1],1,n);
        }
        int ans=0;
        for (int i=1;i<=m;i++)
        {
            int x,d;scanf("%d%d",&x,&d);
            x^=ans; d^=ans; d=min(deep,h[x]+d);
            ans=qurry(root[d],1,n,dfn[x],out[x]);
            printf("%d\n",ans);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/blue_cuso4/article/details/80438613
今日推荐