bzoj4771 七彩树

卧槽调了一晚上

想法很简单

 

用$set$维护不同颜色的树链的并,支持链加和单点查询

具体我们可以差分

于是就是单点加,子树和

考虑深度

我们写一个主席树,第$i$个版本只考虑前$i$层

查询$d + dep[x]$深度的树中$x$子树和即可

 

调调调

想5min写一晚上

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 100010;
int n,m,lastans;
int c[maxn],id[maxn];
int fa[maxn],dep[maxn],size[maxn],bl[maxn];
int ref[maxn],pos[maxn],last[maxn],dfn;
int first[maxn],targ[maxn << 1],nx[maxn << 1],cnt;
inline void add(int u,int v){targ[++cnt] = v,nx[cnt] = first[u],first[u] = cnt;}
inline void ins(int u,int v){add(u,v),add(v,u);}
set<int> cs[maxn];
set<int>::iterator it;
inline void dfs1(int u)
{
    size[u]=1;pos[u] = ++dfn;ref[dfn] = u;
    for(int i=first[u];i;i=nx[i])
    {
        if(targ[i]==fa[u])continue;
        dep[targ[i]]=dep[u]+1;
        fa[targ[i]]=u;
        dfs1(targ[i]);
        size[u]+=size[targ[i]];
    }
    last[u] = dfn;
}
inline void dfs2(int u,int idc)
{
    int k=0;
    bl[u]=idc;
    for(int i=first[u];i;i=nx[i])
        if(dep[targ[i]]>dep[u] && size[targ[i]]>size[k])
            k=targ[i];
    if(k==0)return;
    dfs2(k,idc);
    for(int i=first[u];i;i=nx[i])
        if(dep[targ[i]]>dep[u] && k!=targ[i])
            dfs2(targ[i],targ[i]);
}
inline int lca(int x,int y)
{
    while(bl[x] != bl[y])
    {
        if(dep[bl[x]] < dep[bl[y]])swap(x,y);
        x = fa[bl[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
int root[maxn],ls[maxn << 6],rs[maxn << 6],val[maxn << 6],ToT;
inline void Insert(int &x,int pre,int l,int r,int pos,int v)
{
    x = ++ToT;val[x] = val[pre] + v;
    if(l == r)return;
    int mid = (l + r) >> 1;
    if(pos <= mid)rs[x] = rs[pre],Insert(ls[x],ls[pre],l,mid,pos,v);
    else ls[x] = ls[pre],Insert(rs[x],rs[pre],mid + 1,r,pos,v);
}
inline int query(int x,int l,int r,int L,int R)
{
    if(L <= l && r <= R)return val[x];
    int mid = (l + r) >> 1,ans = 0;
    if(L <= mid)ans += query(ls[x],l,mid,L,R);
    if(R > mid)ans += query(rs[x],mid + 1,r,L,R);
    return ans;
}
bool cmp(int u,int v){return dep[u] < dep[v];}
int main()
{
    int T = read();
    while(T--)
    {
        cnt = 0,dfn = 0,ToT = 0,lastans = 0;
        int p = 1;
        n = read(),m = read();
        for(int i=1;i<=n;i++)c[i] = read(),cs[i].clear(),id[i] = i,first[i] = 0;
        for(int i=2;i<=n;i++){int u = read();ins(u,i);}
        dfs1(1);dfs2(1,1);sort(id + 1,id + n + 1,cmp);
        root[0] = 0;int x,y;
        for(int i=0;i<n;i++)
        {
            if(i)root[i] = root[i - 1];
            while(p <= n && dep[id[p]] <= i)
            {
                x = 0,y = 0;int pcol = c[id[p]];
                it = cs[pcol].lower_bound(pos[id[p]]);
                if(it != cs[pcol].end())y = ref[*it];
                if(it != cs[pcol].begin())x = ref[*--it];
                Insert(root[i],root[i],1,n,pos[id[p]],1);
                if(x)Insert(root[i],root[i],1,n,pos[lca(x,id[p])],-1);
                if(y)Insert(root[i],root[i],1,n,pos[lca(y,id[p])],-1);
                if(x && y)Insert(root[i],root[i],1,n,pos[lca(x,y)],1);
                cs[pcol].insert(pos[id[p]]),++p;
            }
        }
        while(m--)
        {
            x = read(),y = read();
            x = x ^ lastans,y = min(dep[x] + (y ^ lastans),n - 1);
            printf("%d\n" ,lastans = query(root[y],1,n,pos[x],last[x]));
        }
    }
}
View Code

手已经不健康了

posted @ 2018-09-11 20:16  探险家Mr.H  阅读(499)  评论(4编辑  收藏  举报