BZOJ 4771 七彩树 | scz 8.5 逆向思维(强制在线)

题目大意

给一颗\(n\)个节点的有根树,每个节点有一个颜色\(c_i(1 \le c_i \le n)\),设节点\(x\)的深度为\(deep_x\),回答\(m\)次询问,每次询问形如:

  • x d 询问\(x\)子树里深度不超过\(deep_x + d\)的所有节点的颜色种数

\(T\)组测试,每组测试相互独立,强制在线。
\(T \le 500,n,m \le 1 \times 10^5,1 \le \sum n,\sum m \le 5 \times 10^5\)

Solution

考虑没有深度限制怎么做。先将树转化成dfs序,用线段树维护。一开始每个节点都+1,这样显然会有重复,然后将所有颜色相同的点按照dfn排序,利用树链的并维护一下,询问转为子树和(也就是区间求和)。

有深度限制后,对于深度建主席树,从小到大枚举深度,然后将此深度的点加进来维护即可。

时间复杂度\(O(T(n+m)\log n)\)

# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
# define itor set<int>::iterator
template <typename T> void read(T &x)
{
    int w = 1; x = 0;
    char ch = getchar();
    while(!isdigit(ch)) 
    {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(isdigit(ch))
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    x *= w; return;
}
template <typename T> void write(T x)
{
    if(x >= 10) write(x / 10);
    char ch = char(x % 10 + 48);
    putchar(ch);
}
int Test,n,m;
int c[N];
vector <int> g[N];
set <int> Col[N];
int dep[N],f[22][N];
int dfn[N],arcdfn[N],dfntot = 0;
int siz[N];
vector <int> D[N];
struct node
{
    int ls,rs;
    int val;
}T[N << 5];
int rt[N],tot = 0;
int Maxd = 0;
void dfs(int x,int fa)
{
    dep[x] = dep[fa] + 1;
    siz[x] = 1;
    dfn[x] = ++dfntot,arcdfn[dfntot] = x;
    Maxd = max(Maxd,dep[x]);
    D[dep[x]].push_back(x);
    f[0][x] = fa;
    for(int i = 1; i <= 20; i++) f[i][x] = f[i - 1][f[i - 1][x]];
    for(int v : g[x])
    {
        if(v == fa) continue;
        dfs(v,x);
        siz[x] += siz[v];
    }
    return;
}
int LCA(int x,int y)
{
    if(dep[x] > dep[y]) swap(x,y);
    for(int i = 20; i >= 0; i--) 
    {
        if(dep[x] + (1 << i) <= dep[y]) y = f[i][y];
    }
    if(x == y) return x;
    for(int i = 20; i >= 0; i--)
    {
        if(f[i][x] ^ f[i][y]) x = f[i][x],y = f[i][y];
    }
    return f[0][x];
}
//---------------
void pushup(int root)
{
    T[root].val = T[T[root].ls].val + T[T[root].rs].val;
    return;
}
void build(int &root,int l,int r)
{
    if(root == 0) root = ++tot,T[root].ls = T[root].rs = 0;
    if(l == r)
    {
        T[root].val = 0,T[root].ls = T[root].rs = 0;
        return;
    }
    int mid = (l + r) >> 1;
    build(T[root].ls,l,mid),build(T[root].rs,mid + 1,r);
    pushup(root);
    return;
}
void update(int &root,int l,int r,int x,int d)
{
    if(root == 0) root = ++tot,T[root].val = T[root].ls = T[root].rs = 0;
    if(l == r)
    {
        T[root].val += d;
        T[root].ls = T[root].rs = 0;
        return;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) update(T[root].ls,l,mid,x,d);
    else update(T[root].rs,mid + 1,r,x,d);
    pushup(root);
    return;
}
int merge(int root,int pre,int l,int r)
{
    if(root == 0 || pre == 0) return root + pre;
    if(l == r) 
    {
        T[root].val += T[pre].val;
        return root;
    }
    int mid = (l + r) >> 1;
    T[root].ls = merge(T[root].ls,T[pre].ls,l,mid);
    T[root].rs = merge(T[root].rs,T[pre].rs,mid + 1,r);
    pushup(root);
    return root;
}
int query(int L,int R,int l,int r,int s,int t)
{
    if(l <= s && t <= r)
    {
        return T[R].val - T[L].val;
    }
    int mid = (s + t) >> 1;
    int ans = 0;
    if(l <= mid) ans = ans + query(T[L].ls,T[R].ls,l,r,s,mid);
    if(r > mid) ans = ans + query(T[L].rs,T[R].rs,l,r,mid + 1,t);
    return ans; 
}

int main(void)
{
    // freopen("4771.in","r",stdin);
    // freopen("4771.out","w",stdout);
    read(Test);
    for(int _ = 1; _ <= Test; _++)
    {
        read(n),read(m);
        for(int i = 1; i <= n; i++) Col[i].clear();
        for(int i = 1; i <= n; i++)
        {
            read(c[i]);
            g[i].clear();
        }
        for(int i = 2; i <= n; i++)
        {
            int f; read(f);
            g[f].push_back(i),g[i].push_back(f);
        }
        // printf("Test = %d,152:Yes\n",_);
        dep[0] = 0;
        dfntot = 0;
        tot = 0;
        Maxd = 0;
        for(int i = 1; i <= n; i++) D[i].clear();
        dfs(1,0);
        // printf("Test = %d,159:Yes\n",_);
        rt[0] = 0;
        build(rt[0],1,dfntot);
        // printf("Test = %d,tot = %d,161:Yes\n",_,tot);
        // for(int i = 1; i <= n; i++) Col[c[i]].insert(dfn[i]);
        for(int i = 1; i <= Maxd; i++)
        {
            rt[i] = 0;
            for(int x : D[i])
            {
                update(rt[i],1,dfntot,dfn[x],1);   
                itor it = Col[c[x]].lower_bound(dfn[x]);
                int pre = -1,nxt = -1;
                if(it != Col[c[x]].end()) nxt = (*it);
                if(it != Col[c[x]].begin()) {--it; pre = (*it);}
                if(pre != -1) pre = arcdfn[pre];
                if(nxt != -1) nxt = arcdfn[nxt];
                if(pre != -1) update(rt[i],1,dfntot,dfn[LCA(pre,x)],-1);
                if(nxt != -1) update(rt[i],1,dfntot,dfn[LCA(nxt,x)],-1);
                if(pre != -1 && nxt != -1) update(rt[i],1,dfntot,dfn[LCA(pre,nxt)],1);
                Col[c[x]].insert(dfn[x]);
            }
            rt[i] = merge(rt[i],rt[i - 1],1,dfntot);
        }
        int lstans = 0;
        for(int __ = 1; __ <= m; ++__)
        {
            int x,d; scanf("%d%d",&x,&d);
            x = x ^ lstans,d = d ^ lstans;
            int Dep = min(dep[x] + d,Maxd);
            int Left = dfn[x],Right = dfn[x] + siz[x] - 1;
            write(lstans = query(0,rt[Dep],Left,Right,1,dfntot)); putchar('\n');
        }
    }
    return 0;
}
posted @ 2022-08-24 16:41  luyiming123  阅读(21)  评论(0编辑  收藏  举报