hdu5709 Claris Loves Painting

给一棵 n 点的树,每个节点上有一个颜色 (c_i) ,q 次询问一个点的子树中与这个点距离不
超过 d 的点的颜色有多少种。
(强制在线)

考虑开两棵线段树

第一棵中的每个点维护这个点的子树内深度在([l,r])之间有多少个点

第二棵的每个点维护这个点的子树内每种颜色的最小深度

我们从叶子节点向上合并,先合并第一棵再合并第二棵,如果合并第二棵时有两个颜色相等的节点,就保留深度小的并在第一棵线段树里减去这个点的贡献

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 5e5;
using namespace std;
int T,n,m,c[N + 5],f[N + 5],dep[N + 5],rt1[N + 5],rt2[N + 5],node_cnt,val[N * 40 + 5],lc[N * 40 + 5],rc[N * 40 + 5];
inline int read()
{
	int X(0),w(0);char ch(0);
	while (!isdigit(ch))w|=ch=='-',ch=getchar();
	while (isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
void insert(int &k,int las,int l,int r,int x,int v)
{
    k = ++node_cnt;
    val[k] = val[las] + v;
    lc[k] = lc[las];
    rc[k] = rc[las];
    if (l == r)
        return;
    int mid = l + r >> 1;
    if (x <= mid)
        insert(lc[k],lc[las],l,mid,x,v);
    else
        insert(rc[k],rc[las],mid + 1,r,x,v);
}
int merge1(int x,int y)
{
    if (!x || !y)
        return x + y;
    int z = ++node_cnt;
    val[z] = val[x] + val[y];
    lc[z] = merge1(lc[x],lc[y]);
    rc[z] = merge1(rc[x],rc[y]);
    return z;
}
int merge2(int x,int y,int l,int r,int k)
{
    if (!x || !y)
        return x + y;
    int z = ++node_cnt;
    if (l == r)
    {
        val[z] = min(val[x],val[y]);
        if (val[x] < val[y])
            insert(rt1[k],rt1[k],1,n,val[y],-1);
        else
            insert(rt1[k],rt1[k],1,n,val[x],-1);
        return z;
    }
    int mid = l + r >> 1;
    lc[z] = merge2(lc[x],lc[y],l,mid,k);
    rc[z] = merge2(rc[x],rc[y],mid + 1,r,k);
    return z;
}
int query(int k,int l,int r,int x)
{
    if (!k)
        return 0;
    if (r <= x)
        return val[k];
    int mid = l + r >> 1;
    if (x <= mid)
        return query(lc[k],l,mid,x);
    else
        return query(lc[k],l,mid,x) + query(rc[k],mid + 1,r,x);
}
int main()
{
    T = read();
    while (T--)
    {
        n = read();
        m = read();
        for (int i = 1;i <= n;i++)
            c[i] = read();
        dep[1] = 1;
        for (int i = 2;i <= n;i++)
            f[i] = read(),dep[i] = dep[f[i]] + 1;
        for (int i = 1;i <= n;i++)
        {
            insert(rt1[i],0,1,n,dep[i],1);
            insert(rt2[i],0,1,n,c[i],dep[i]);
        }
        for (int i = n;i >= 2;i--)
        {
            rt1[f[i]] = merge1(rt1[i],rt1[f[i]]);
            rt2[f[i]] = merge2(rt2[i],rt2[f[i]],1,n,f[i]);
        }
        int ans = 0;
        int x,d;
        while (m--)
        {
            x = read();
            d = read();
            x ^= ans;
            d ^= ans;
            d = min(n,d + dep[x]);
            ans = query(rt1[x],1,n,d);
            printf("%d
",ans);
        }
        ans = node_cnt = 0;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdlang/p/13428560.html