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\n",ans);
}
ans = node_cnt = 0;
}
return 0;
}