[BZOJ4771] 七彩樹 [可持久化線段樹][dfs序][set]

[Link\frak{Link}]


樹上數顏色我們可以考慮用 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章