BZOJ 七彩树

written on 2022-05-02

传送!

问题我想留在开头:为什么主席树的空间开45倍都过不了,要开50?

题目最大的困难在于有深度限制,而且强制在线,否则就是裸的线段树合并了

既然题目大胆地给了深度限制,那么这题大胆的正解之一就是把点按照深度从小到大排序,用主席树来维护区间和。

哇塞好恐怖!

在循环的时候,还要考虑重复的点对答案的影响,这个时候,发现两个颜色相同的点重复的部分,就在于他们的lca(因为主席树是以前缀和的形式维护的)。

于是从浅到深枚举,每次加入一个颜色的点,还要消除与它相邻的两个同颜色点的影响,这个可以用set维护dfs序。(注意:这个点相邻的两个点lca要加一,因为上一次减了1,这次要消回来)

查询时为了方便,rt 的下标肯定是深度,也就是说,在这棵子树内( dfn[x]~dfn[x]+siz[x]1),查询下标为最深点的主席树的值,那么怎么维护这棵主席树就可以明白了吧

写这篇题解好累,不懂的就看代码吧,写得还算看的过去

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,m;
int tot,ver[N],nxt[N],head[N];
void add_E(int x,int y){ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;}
int c[N],dep[N];
struct F{int id,col,dep;}b[N];
bool cmp(F a,F b){return a.dep<b.dep;}
int f[N][20];
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=19;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
int dfn[N],rnk[N],siz[N],rt[N],mx;
void dfs(int x)
{
	for(int i=1;i<=19;i++) f[x][i]=f[f[x][i-1]][i-1];
	dfn[x]=++tot,rnk[tot]=x;
	b[x].dep=dep[x],siz[x]=1;
	mx=max(mx,dep[x]);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];
		dep[y]=dep[x]+1;
		dfs(y);
		siz[x]+=siz[y];
	}
}
struct Seg
{
	int tot,ls[N*55],rs[N*55],val[N*55];//所以为什么空间要开到55? 
	int build(int l,int r)
	{
		int p=++tot;
		ls[p]=rs[p]=val[p]=0;
		if(l==r) return p;
		int mid=l+r>>1;
		ls[p]=build(l,mid),rs[p]=build(mid+1,r);
		return p;
	}
	int New(int lst,int l,int r,int x,int v)
	{
		int p=++tot;
		ls[p]=ls[lst],rs[p]=rs[lst],val[p]=val[lst];
		if(l==r)
		{
			val[p]+=v;
			return p;
		}
		int mid=l+r>>1;
		if(x<=mid) ls[p]=New(ls[p],l,mid,x,v);
		else rs[p]=New(rs[p],mid+1,r,x,v);
		val[p]=val[ls[p]]+val[rs[p]];
		return p;
	}
	int ask(int p,int l,int r,int L,int R)
	{
		if(L<=l&&R>=r) return val[p];
		int mid=l+r>>1,res=0;
		if(L<=mid) res+=ask(ls[p],l,mid,L,R);
		if(R>mid) res+=ask(rs[p],mid+1,r,L,R);
		return res;
	}
}t1;
set<int> s[N];
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		mx=tot=0,memset(head,0,sizeof(head));
		t1.tot=0;
		memset(rt,0,sizeof(rt));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&c[i]);
			b[i].col=c[i],b[i].id=i;
			s[i].clear();
		}
		for(int i=2;i<=n;i++)
		{
			scanf("%d",&f[i][0]);
			add_E(f[i][0],i);
		}
		tot=0,dep[1]=1,dfs(1);
		rt[0]=t1.build(1,n);
		sort(b+1,b+1+n,cmp);
		for(int i=1;i<=n;i++)
		{
			if(b[i].dep==b[i-1].dep) rt[b[i].dep]=t1.New(rt[b[i].dep],1,n,dfn[b[i].id],1);
			else rt[b[i].dep]=t1.New(rt[b[i-1].dep],1,n,dfn[b[i].id],1);
			set<int>::iterator it=s[b[i].col].lower_bound(dfn[b[i].id]);
			t1.New(rt[b[i].dep],1,n,dfn[b[i].id],1);
			int x=0,y=0;
			if(it!=s[b[i].col].end())
			{
				x=*it;
				int l=lca(rnk[x],b[i].id);
				rt[b[i].dep]=t1.New(rt[b[i].dep],1,n,dfn[l],-1);
			}
			if(it!=s[b[i].col].begin())
			{
				y=*(--it);
				int l=lca(rnk[y],b[i].id);
				rt[b[i].dep]=t1.New(rt[b[i].dep],1,n,dfn[l],-1);
			}
			if(x&&y)
			{
				int l=lca(rnk[x],rnk[y]);
				rt[b[i].dep]=t1.New(rt[b[i].dep],1,n,dfn[l],1);
			}
			s[b[i].col].insert(dfn[b[i].id]);
		}
		int ans=0;
		for(int i=1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			x=x^ans,y=y^ans;
			printf("%d\n",ans=t1.ask(rt[min(mx,dep[x]+y)],1,n,dfn[x],dfn[x]+siz[x]-1));
		}
	}
}
posted @   Freshair_qprt  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示