[loj6868]种苹果

在树上随机选\(K\)个点,并建立虚树,称虚树上的点为关键点

结论:一个点到关键点最近距离的期望为\(O(\frac{n}{K})\)

将所有点按到其距离排序,最坏情况即链的端点,此时结论是经典的

对于后两种操作,可以将两个点不断移动到父亲,直至两者相同或位于关键点

将相邻关键点间的链看作整块,每条边看作散块,即类似序列上的问题

维护整块权值的有序数组:整块修改懒标记、散块修改归并、整块查询二分、散块查询暴力

对于前两种操作,可能会影响结论中的性质,因此需要每\(D\)次操作重构,单次重构为\(O(n\log n)\)

时间复杂度为\(O(mK\log n+m(\frac{n}{K}+D)+\frac{nm}{D}\log n)\)

\(\begin{cases}K=\sqrt{\frac{n}{\log n}}\\D=\sqrt{n\log n}\end{cases}\)时取到最小,时间复杂度为\(O(m\sqrt{n\log n})\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
const int N=400005;
int n,m,t,K,D,p,x,y,z,ans,fa[N],id[N],vis[N],bl[N],Fa[N],Vis[N];
ll a[N],tag[N];
vi vx,vy,v0,v1,e[N],v[N];
mt19937 rng(0);
void dfs(int k,int f){
	fa[k]=f;
	for(int i:e[k])
		if (i!=f)dfs(i,k);
}
void dfs1(int k){
	int s=0;
	for(int i:e[k]){
		dfs1(i);
		if (bl[i])s++;
	}
	if (s>1)vis[k]=1;
	if (vis[k])bl[k]=++t;
	else{
		vis[k]=bl[k]=0;
		for(int i:e[k])bl[k]|=bl[i];
	}
	if (bl[k])v[bl[k]].push_back(k);
}
void dfs2(int k,int lst){
	if (vis[k])Fa[k]=lst,lst=k;
	for(int i:e[k])dfs2(i,lst);
}
bool cmp(int x,int y){
	return a[x]<a[y];
}
void build(){
	D=(int)sqrt(n*log(n+1));
	for(int i=1;i<=n;i++)e[i].clear();
	for(int i=2;i<=n;i++)e[fa[i]].push_back(i);
	for(int i=1;i<=n;i++)id[i]=i;
	shuffle(id+1,id+n+1,rng);
	memset(vis,0,sizeof(vis));
	vis[1]=1;
	for(int i=1;i<=K;i++)vis[id[i]]=1;
	for(int i=1;i<=t;i++){
		for(int j:v[i])a[j]+=tag[i];
		tag[i]=0,v[i].clear();
	}
	t=0,dfs1(1),dfs2(1,0);
	for(int i=1;i<=t;i++)sort(v[i].begin(),v[i].end(),cmp);
}
void get_link(int x,int y){
	v0.clear(),v1.clear();
	int x0=x,y0=y;
	while (!vis[x0])x0=fa[x0];
	while (!vis[y0])y0=fa[y0];
	for(int i=x0;i;i=Fa[i])vis[i]=-1;
	int k=y0;
	while (vis[k]>0)k=Fa[k];
	for(int i=x0;i;i=Fa[i])vis[i]=1;
	if (k!=x0){
		while (x!=x0)v1.push_back(x),x=fa[x];
		while (Fa[x]!=k)v0.push_back(bl[x]),x=Fa[x];
	}
	if (k!=y0){
		while (y!=y0)v1.push_back(y),y=fa[y];
		while (Fa[y]!=k)v0.push_back(bl[y]),y=Fa[y];
	}
	for(int i=x;i!=k;i=fa[i])vis[i]-=2;
	vis[k]-=2;
	while (vis[y]>=0)v1.push_back(y),y=fa[y];
	for(int i=x;i!=k;i=fa[i])vis[i]+=2;
	vis[k]+=2;
	while (x!=y)v1.push_back(x),x=fa[x];
	v1.push_back(x);
}
void upd(int k){
	vx.clear(),vy.clear();
	for(int i:v[k]){
		if (vis[i]<0)vx.push_back(i);
		else vy.push_back(i);
	}
	int sx=vx.size(),sy=vy.size();
	for(int i=0,j=0;(i<sx)||(j<sy);){
		if ((i<sx)&&((j==sy)||(cmp(vx[i],vy[j]))))v[k][i+j]=vx[i],i++;
		else v[k][i+j]=vy[j],j++;
	}
}
int query(int k,int x){
	a[0]=x-tag[k];
	return v[k].end()-lower_bound(v[k].begin(),v[k].end(),0,cmp);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x); 
	}
	K=(int)sqrt(n/log(n+1));
	dfs(1,0),build();
	for(int i=1;i<=m;i++){
		scanf("%d",&p);
		if (p==1){
			scanf("%d%d%lld",&x,&y,&a[++n]);
			x^=ans,y^=ans,a[n]^=ans;
			if (fa[x]==y)swap(x,y);
			fa[n]=x,fa[y]=n;
			if (bl[y]){
				a[n]-=tag[bl[y]],bl[n]=bl[y];
				v[bl[n]].push_back(n);
				vis[n]=-1,upd(bl[n]),vis[n]=0;
			}
			if (--D==0)build();
		}
		if (p==2){
			n++;
			scanf("%d%lld",&fa[n],&a[n]);
			fa[n]^=ans,a[n]^=ans;
			if (--D==0)build();
		}
		if (p==3){
			scanf("%d%d%d",&x,&y,&z);
			x^=ans,y^=ans,z^=ans;
			get_link(x,y);
			for(int i:v0)tag[i]+=z;
			for(int i:v1)a[i]+=z,vis[i]-=2;
			for(int i:v1)
				if ((bl[i])&&(!Vis[bl[i]]))Vis[bl[i]]=1,upd(bl[i]);
			for(int i:v1){
				vis[i]+=2;
				if (bl[i])Vis[bl[i]]=0;
			}
		}
		if (p==4){
			scanf("%d%d%d",&x,&y,&z);
			x^=ans,y^=ans,z^=ans;
			ans=0,get_link(x,y);
			for(int i:v0)ans+=query(i,z);
			for(int i:v1)ans+=(a[i]+tag[bl[i]]>=z);
			printf("%d\n",ans);
		}
	}
	return 0;
} 
posted @ 2023-03-10 14:43  PYWBKTDA  阅读(165)  评论(0编辑  收藏  举报