树上数颜色我们可以考虑用 dfs 序转化成统计区间颜色数
现在多了深度的限制,显然我们又可以把深度区间查询转化为前缀和查询
深度随时可能不同 那显然可以用主席树
预处理一下每个点子树在 dfs 序上的范围就好了
第一步怎么做?
我们考虑把统计子树颜色数换一下,变成区间求和
那就要保证出了子树之后就数不到这种颜色了
而且要保证子树内每种颜色只贡献 1
所以简单容斥。容斥需要用到一个 set 来维护。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cctype>
#include<ctime>
#include<set>
#include<vector>
using namespace std;
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
inline void read(int& x)
{
x = 0; register char ch = getchar(); register bool w = 0;
while (!isdigit(ch)) w |= (ch == '-'), ch = getchar();
while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
w ? (x=-x) : 0;
}
const int MAXN = 1e5+5;
int n, m, Ans, tot, col[MAXN], fa[MAXN], SegTot, Dep;
int head[MAXN], nxt[MAXN], to[MAXN], DfsId[MAXN];
int DfsStack[MAXN], Depth[MAXN];
int ConRig[MAXN];
set<int> ColLst[MAXN];
int DepLst[MAXN];
inline bool cmp(const int& a, const int& b)
{
return Depth[a] < Depth[b];
}
#define add_edge(a,b) nxt[++tot]=head[a], head[a]=tot, to[tot]=b
int Rt[MAXN];
const int MAXS = MAXN << 7;
int Child[MAXS][2], Seg[MAXS];
#define LChild(x) Child[x][0]
#define RChild(x) Child[x][1]
void Insert(int& Pos, int L, int R, const int& x, const int& w, const int& tDep)
{
if (L > R) return;
++SegTot;
LChild(SegTot) = LChild(Pos);
RChild(SegTot) = RChild(Pos);
Seg[SegTot] = Seg[Pos];
Pos = SegTot;
Seg[Pos] += w;
if (L == R) return;
int Mid = L + R >> 1;
if (x <= Mid) Insert(LChild(Pos), L, Mid, x, w, tDep);
else Insert(RChild(Pos), Mid + 1, R, x, w, tDep);
}
int Siz[MAXN], BigSon[MAXN];
void Dfs(int x)
{
DfsStack[++DfsStack[0]] = x;
DfsId[x] = DfsStack[0];
Siz[x] = 1;
BigSon[x] = 0;
for (register int i = head[x]; i; i = nxt[i])
{
Depth[to[i]] = Depth[x] + 1;
Dfs(to[i]);
Siz[x] += Siz[to[i]];
if (Siz[to[i]] > Siz[BigSon[x]]) BigSon[x] = to[i];
}
ConRig[x]=DfsStack[0];
}
int Top[MAXN];
void Divide(int x, int tp)
{
Top[x] = tp;
if (BigSon[x]) Divide(BigSon[x], tp);
for (register int i = head[x]; i; i = nxt[i])
{
if (to[i] != BigSon[x]) Divide(to[i], to[i]);
}
}
inline int LCA(int x, int y)
{
while (Top[x]^Top[y])
{
Depth[Top[x]] < Depth[Top[y]] ? y = fa[Top[y]] : x = fa[Top[x]];
}
return Depth[x] < Depth[y] ? x : y;
}
int Query(int Pos, int L, int R, const int& qL, const int& qR)
{
if (!Pos) return 0;
if (L >= qL && R <= qR) return Seg[Pos];
if (L > qR || R < qL) return 0;
int Mid = L + R >> 1;
return Query(LChild(Pos),L,Mid,qL,qR) + Query(RChild(Pos),Mid+1,R,qL,qR);
}
int main()
{
int T, x, d;
read(T);
Depth[1] = 1;
while (T--)
{
Ans = Dep = 0;
SegTot = tot = DfsStack[0] = 0;
read(n); read(m);
for (register int i = 1; i <= n; ++i)
{
Siz[i] = 0;
ColLst[i].clear();
head[i] = 0;
Rt[i] = 0;
}
for (register int i = 1; i <= n; ++i) read(col[i]);
for (register int i = 2; i <= n; ++i)
{
read(fa[i]);
if (fa[i]) add_edge(fa[i],i);
}
Dfs(1);
Divide(1, 1);
for (register int i = 1; i <= n; ++i)
{
if (Depth[i] > Dep) Dep = Depth[i];
DepLst[i] = i;
}
sort(DepLst+1, DepLst+1+n, cmp);
register set<int>::iterator Lef, Rig, Cur;
register bool boola, boolb;
for (register int siz, k, j = 1, i = 1; i <= Dep; ++i)
{
Rt[i] = Rt[i-1];
while (j <= n && Depth[DepLst[j]] == i)
{
k = DepLst[j];
Insert(Rt[i], 1, n, DfsId[k], 1, i);
ColLst[col[k]].insert(DfsId[k]);
Cur = ColLst[col[k]].find(DfsId[k]);
Lef = Rig = Cur;
--Lef; ++Rig;
boola = (Cur != ColLst[col[k]].begin());
boolb = (Rig != ColLst[col[k]].end());
if (boola) Insert(Rt[i], 1, n, DfsId[LCA(DfsStack[*Lef], k)], -1, i);
if (boolb) Insert(Rt[i], 1, n, DfsId[LCA(DfsStack[*Rig], k)], -1, i);
if (boola&&boolb) Insert(Rt[i], 1, n, DfsId[LCA(DfsStack[*Lef], DfsStack[*Rig])], 1, i);
++j;
}
}
while (m--)
{
read(x); read(d);
x ^= Ans; d ^= Ans;
printf("%d\n", Ans=Query(Rt[min(Dep,Depth[x]+d)], 1, n, DfsId[x], ConRig[x]));
}
}
return 0;
}