主席树+差分
如果没有深度限制的话,显然有一种维护方式:对于每一种点,用差分来搞,给自己+1,给同一颜色的前驱和自己的LCA-1,给同一颜色的后继和自己的LCA-1,然后查子树和。
加了深度限制就坑爹了。直接用dfs序维护不了,因为询问区间不连续。
考虑每一个询问,我们只希望所有深度不超过dep[x]+d的点有贡献,希望上述的维护只针对前几层的点。因此我们考虑按层来预处理信息。然后用一个能资瓷加和查的数据结构。
得到算法:对于每一层,按dfs序维护一个主席树,维护前几层的信息和。询问时只需查询某一层的主席树上dfs在某一区间的和即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define N 100005
using namespace std;
namespace runzhe2000
{
int read()
{
int r = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar());
for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
return r;
}
int n, m, last[N], ecnt, c[N], q[N];
int beg[N], end[N], timer, dep[N], siz[N], fa[N], son[N], top[N];
struct Pair
{
int fir, sec;
bool operator < (const Pair &that) const {if(fir != that.fir) return fir < that.fir; else return sec < that.sec;}
};
struct edge{int next, to;}e[N];
void addedge(int a, int b){e[++ecnt]=(edge){last[a],b};last[a]=ecnt;}
void dfs1(int x)
{
x == 1 ? dep[x] = 0 : dep[x] = dep[fa[x]] + 1; siz[x] = 1; beg[x] = ++timer;
for(int i = last[x]; i; i = e[i].next)
{
int y = e[i].to; fa[y] = x; dfs1(y); siz[x] += siz[y];
siz[y] > siz[son[x]] ? son[x] = y : 0;
}
end[x] = timer;
}
void dfs2(int x)
{
top[x] = son[fa[x]]==x ? top[fa[x]] : x;
for(int i = last[x]; i; i = e[i].next) dfs2(e[i].to);
}
int get_lca(int a, int b)
{
for(; top[a] != top[b]; ) dep[top[a]] < dep[top[b]] ? b = fa[top[b]] : a = fa[top[a]];
return dep[a] < dep[b] ? a : b;
}
struct seg
{
seg *ls, *rs;
int sum;
}mem[N*200], *root[N]; int mem_tot;
seg* newnode(int sum = 0){return &(mem[mem_tot++] = (seg){NULL, NULL, sum});}
void pushup(seg *p){p->sum = 0; p->ls ? p->sum += p->ls->sum : 0; p->rs ? p->sum += p->rs->sum : 0; }
void modi(seg *&x, int l, int r, int p, int v)
{
x == NULL ? x = newnode() : 0;
if(l == r) {x->sum += v; return;} int mid = (l+r)>>1;
p <= mid ? modi(x->ls, l, mid, p, v) : modi(x->rs, mid+1, r, p, v);
pushup(x);
}
set<Pair> s[N];
set<Pair>::iterator it1, it2;
seg *merge(seg *x, seg *y) // not modify x
{
if(!x || !y) return x ? x : y;
y->sum += x->sum;
y->ls = merge(x->ls, y->ls);
y->rs = merge(x->rs, y->rs);
return y;
}
int query(seg *x, int l, int r, int ql, int qr)
{
if(x == NULL) return 0; if(ql <= l && r <= qr) return x->sum;
int mid = (l+r)>>1, ret = 0;
if(ql <= mid) ret += query(x->ls, l, mid, ql, qr);
if(mid < qr) ret += query(x->rs, mid+1, r, ql, qr);
return ret;
}
void clr()
{
ecnt = timer = mem_tot = 0;
memset(last, 0, sizeof(last));
memset(son, 0, sizeof(son));
memset(q, 0, sizeof(son));
}
void main()
{
for(int T = read(); T--; )
{
n = read(); m = read(); clr();
for(int i = 1; i <= n; i++) c[i] = read(), s[c[i]].clear();
for(int i = 2; i <= n; i++) addedge(read(), i);
dfs1(1); dfs2(1); q[0] = 1;
int cur = 0; root[0] = newnode();
for(int head=0,tail=1; head<tail; head++)
{
int x = q[head], col = c[x]; bool havel, haver;
for(int i = last[x]; i; i = e[i].next) q[tail++] = e[i].to;
modi(root[cur], 1, n, beg[x], 1);
it1 = s[col].lower_bound((Pair){beg[x], x});
it1 == s[col].begin() ? havel = 0 : (--it1, havel = 1);
it2 = s[col].upper_bound((Pair){beg[x], x});
it2 == s[col].end() ? haver = 0 : haver = 1;
s[col].insert((Pair){beg[x],x});
if(havel) modi(root[cur], 1, n, beg[get_lca(it1->sec, x)], -1);
if(haver) modi(root[cur], 1, n, beg[get_lca(it2->sec, x)], -1);
if(havel && haver) modi(root[cur], 1, n, beg[get_lca(it1->sec, it2->sec)], 1);
if(dep[q[head+1]] != dep[x])
{
if(cur) root[cur] = merge(root[cur-1], root[cur]);
root[++cur] = newnode();
}
}
int max_dep = dep[q[n-1]];
for(int ans = 0, x, d; m--; )
{
x = read()^ans; d = read()^ans;
d = min(dep[x] + d, max_dep);
printf("%d\n",ans = query(root[d],1,n,beg[x],end[x]));
}
}
}
}
int main()
{
runzhe2000::main();
}