其他分享
首页 > 其他分享> > UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap

UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap

作者:互联网

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ55.html

题解

做法还是挺容易想到的。

但是写的话……

首先这种题如果只要求一棵树中的满足条件的点数(不需要在加点的同时维护答案),那么显然可以点分治:

假设当前点分中心为 x,设点 y 与 x 的距离为 d[y] ,然后,我们把 $d[a] + d[b] \leq r[a] + r[b]$ 移一下项,得到:

$$d[a]-r[a]\leq r[b] - d[b]$$

那么,我们只需要对于每一个点 b 求出与它不在 x 的同一个子树的节点 a 的个数,a 要满足 $d[a]-r[a]\leq r[b]-d[b]$ 。这个东西显然是可以用数据结构维护的。

具体用什么呢?

再说。

 

现在我们要动态维护答案。考虑如果可以离线怎么做:

对最终的树建一个点分树,也就是搞一个动态点分治。对于每一个点分中心,维护他控制的区域内所有节点的 d[a]-r[a] ;对于他的每一个子树,也维护一下这个东西。

那么加入一个点的时候,我们只要在点分树上走一趟,通过维护的信息更新答案的同时加入当前节点的贡献。

所以我们要的数据结构得支持插入和询问排名,那么自然选用平衡树。

所以离线的复杂度是 $O(n\log^2 n)$ 。

 

然而题目要求强制在线。

怎么办?

定期重构点分树?复杂度好像是 $O(n\sqrt n \log  n)$ 。好像和暴力得分一样……

 

定期重构太naive了,我们给他升个级!

替罪羊树:当点分树的一个子树划分的过度不均匀的时候,重构子树。

 

恭喜你得到了一个 $O(n\log^3 n)$ 的算法。

接下来是写代码和调代码的欢♂乐时光。

 

可怕的是,这题还卡常数……

下面给出两份代码,一个是splay(68331ms的那个),一个是非旋Treap(107878ms)。

代码1 - splay

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
using namespace std;
typedef long long LL;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=100005,INF=1.05e9,mod=1e9;
const double checkval=0.80;
namespace spl{
	const int S=N*100;
	int son[S][2],fa[S],val[S],size[S];
	int cnt=0;
	namespace cly{
		int st[S],top=0;
		inline int new_node(){
			return top?st[top--]:++cnt;
		}
		inline void Recover(int x){
			st[++top]=x;
			son[x][0]=son[x][1]=fa[x]=val[x]=size[x]=0;
		}
	}
	using cly::new_node;
	using cly::Recover;
	#define ls son[x][0]
	#define rs son[x][1]
	int new_node(int v){
		int x=new_node();
		val[x]=v;
		return x;
	}
	inline void pushup(int x){
		size[x]=size[ls]+size[rs]+1;
	}
	inline int wson(int x){
		return son[fa[x]][1]==x;
	}
	void rotate(int x){
		int y=fa[x],z=fa[y],L=son[y][1]==x,R=L^1;
		if (z)
			son[z][son[z][1]==y]=x;
		fa[x]=z,fa[y]=x,fa[son[x][R]]=y;
		son[y][L]=son[x][R],son[x][R]=y;
		pushup(y),pushup(x);
	}
	void splay(int x){
		for (int y=fa[x];fa[x];rotate(x),y=fa[x])
			if (fa[y])
				rotate(wson(x)==wson(y)?y:x);
	}
	inline void Ins(int &a,int v){
		register int x=a,c=0;
		int f=0;
		while (x){
			c++;
			size[x]++;
			f=x;
			x=v<val[x]?ls:rs;
		}
		val[son[f][v>=val[f]]=x=new_node()]=v,fa[x]=f,size[x]=1;
		if (!a||c>30)
			splay(a=x);
	}
	int Query(int &rt,int v){
		int ans=0,c=0;
		register int x=rt,p=0;
		while (x){
			p=x,c++;
			if (val[x]<=v)
				ans+=size[ls]+1,x=rs;
			else
				x=ls;
		}
		if (p&&c>30)
			splay(rt=p);
		return ans;
	}
	void Remove(int x){
		if (x)
			Remove(ls),Remove(rs),Recover(x);
	}
	int id[N];
	void Build(int &x,int L,int R,int f){
		if (L>R)
			return;
		int mid=(L+R)>>1;
		fa[x=id[mid]]=f;
		Build(ls,L,mid-1,x);
		Build(rs,mid+1,R,x);
		pushup(x);
	}
	void Build(int &x,vector <int> &v){
		if (v.empty())
			return;
		int n=0;
		sort(v.begin(),v.end());
		for (auto i : v)
			id[++n]=new_node(i);
		Build(x,1,n,0);
	}
	#undef ls
	#undef rs
}
int Test,n;
LL ans=0;
vector <int> e[N];
int fa[N][20],depth[N],len[N];
int LCA(int x,int y){
	if (depth[x]<depth[y])
		swap(x,y);
	Fod(i,16,0)
		if (depth[x]-(1<<i)>=depth[y])
			x=fa[x][i];
	if (x==y)
		return x;
	Fod(i,16,0)
		if (fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
int Dis(int x,int y){
	return len[x]+len[y]-2*len[LCA(x,y)];
}
int r[N];
namespace dt{
	int fa[N],size[N],mxs[N],depth[N];
	int rt[N],rtf[N];
	int node_cnt=0;
	void Init(){
		clr(fa),clr(size),clr(mxs),clr(depth),clr(rt),clr(rtf);
		depth[0]=-1,node_cnt++;
		size[1]=1,mxs[1]=depth[1]=rt[1]=0;
		spl::Ins(rt[1],0-r[1]);
	}
	int id[N],idc=0;
	void dfs(int x,int pre,int d){
		id[++idc]=x;
		for (auto y : e[x])
			if (y!=pre&&depth[y]>=d)
				dfs(y,x,d);
	}
	int sz[N],msz[N],RT,Size;
	void dfs2(int x,int pre){
		sz[x]=1,msz[x]=0;
		for (auto y : e[x])
			if (y!=pre&&!size[y]){
				dfs2(y,x);
				sz[x]+=sz[y];
				msz[x]=max(msz[x],sz[y]);
			}
		msz[x]=max(msz[x],Size-sz[x]);
		if (!RT||msz[x]<msz[RT])
			RT=x;
	}
	vector <int> id1,id2;
	void dfs3(int x,int pre,int anc){
		sz[x]=1;
		id1.pb(Dis(x,anc)-r[x]);
		if (fa[anc])
			id2.pb(Dis(x,fa[anc])-r[x]);
		for (auto y : e[x])
			if (y!=pre&&!size[y])
				dfs3(y,x,anc),sz[x]+=sz[y];
	}
	void build(int x,int f,int n){
		RT=0,Size=n;
		dfs2(x,0);
		x=RT;
		fa[x]=f,depth[x]=depth[f]+1,size[x]=n,mxs[x]=msz[x];
		id1.clear(),id2.clear();
		dfs3(x,0,x);
		spl::Build(rt[x],id1);
		spl::Build(rtf[x],id2);
		for (auto y : e[x])
			if (!size[y])
				build(y,x,sz[y]);
	}
	void Rebuild(int x,int f){
		idc=0;
		dfs(x,0,depth[x]);
		For(_t,1,idc){
			int i=id[_t];
			spl::Remove(rt[i]),spl::Remove(rtf[i]);
			depth[i]=size[i]=fa[i]=mxs[i]=rt[i]=rtf[i]=0;
		}
		build(x,f,idc);
	}
	void Ins(int x,int f){
		static vector <int> v;
		fa[x]=f,depth[x]=depth[f]+1;
		rt[x]=rtf[x]=0;
		v.clear();
		for (int i=x;i;i=fa[i]){
			v.pb(i),size[i]++;
			mxs[fa[i]]=max(mxs[fa[i]],size[i]);
			spl::Ins(rt[i],Dis(i,x)-r[x]);
			if (fa[i])
				spl::Ins(rtf[i],Dis(fa[i],x)-r[x]);
		}
		node_cnt++;
		reverse(v.begin(),v.end());
		for (auto i : v)
			if (mxs[i]>checkval*size[i]){
				Rebuild(i,fa[i]);
				break;
			}
		if (size[x]>1)
			ans+=spl::Query(rt[x],r[x])-1;
		for (int i=x,f,d;depth[i];i=f){
			f=fa[i],d=Dis(f,x);
			ans+=spl::Query(rt[f],r[x]-d)-spl::Query(rtf[i],r[x]-d);
		}
	}
}
int main(){
	Test=read(),n=read();
	For(i,1,n){
		int f=read()^(ans%mod),c=read();
		r[i]=read();
		if (!f){
			dt::Init();
			printf("%lld\n",ans);
			continue;
		}
		assert(1<=f&&f<i);
		e[i].pb(f),e[f].pb(i);
		fa[i][0]=f;
		For(j,1,16)
			fa[i][j]=fa[fa[i][j-1]][j-1];
		depth[i]=depth[f]+1;
		len[i]=len[f]+c;
		dt::Ins(i,f);
		printf("%lld\n",ans);
	}
	return 0;
}

  

代码2 - Treap(非旋)

 

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
using namespace std;
typedef long long LL;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=100005,INF=1.05e9,mod=1e9;
const double checkval=0.80;
int randint(){
	#ifdef windows
		return (rand()<<15)^rand();
	#else
		return rand();
	#endif
}
namespace Treap{
	const int S=N*100;
	int son[S][2],val[S],ckv[S],size[S];
	int cnt=0;
	namespace cly{
		int st[S],top=0;
		inline int new_node(){
			return top?st[top--]:++cnt;
		}
		inline void Recover(int x){
			st[++top]=x,son[x][0]=son[x][1]=val[x]=size[x]=0;
		}
	}
	#define ls son[x][0]
	#define rs son[x][1]
	int new_node(int v){
		int x=cly::new_node();
		val[x]=v,ckv[x]=randint(),size[x]=1;
		return x;
	}
	void pushup(int x){
		size[x]=size[ls]+size[rs]+1;
	}
	int Merge(int x,int y){
		if (!x||!y)
			return x+y;
		if (ckv[x]<ckv[y]){
			son[x][1]=Merge(son[x][1],y),pushup(x);
			return x;
		}
		else {
			son[y][0]=Merge(x,son[y][0]),pushup(y);
			return y;
		}
	}
	pair <int,int> Split(int x,int k){
		if (!x)
			return mp(0,0);
		if (k<=size[ls]){
			pair <int,int> p=Split(ls,k);
			ls=p.se,pushup(x);
			return mp(p.fi,x);
		}
		else {
			pair <int,int> p=Split(rs,k-size[ls]-1);
			rs=p.fi,pushup(x);
			return mp(x,p.se);
		}
	}
	int _Rank(int x,int v){
		return x?(val[x]>v?_Rank(ls,v):size[ls]+1+_Rank(rs,v)):0;
	}
	int Rank(int x,int v){
		return _Rank(x,v-1);
	}
	int Query(int x,int v){
		return _Rank(x,v);
	}
	int id[N];
	int tL[N],tR[N],lcnt,rcnt;
	void Build(int &x,int L,int R){
		if (L>R)
			return;
		int Mi=L;
		For(i,L+1,R)
			if (ckv[id[i]]<ckv[id[Mi]])
				Mi=i;
		swap(id[Mi],id[R]);
		x=id[R];
		lcnt=rcnt=0;
		For(i,L,R-1)
			if (val[id[i]]<=val[x])
				tL[++lcnt]=id[i];
			else
				tR[++rcnt]=id[i];
		int c=L-1;
		For(i,1,lcnt)
			id[++c]=tL[i];
		int mid=c;
		For(i,1,rcnt)
			id[++c]=tR[i];
		Build(ls,L,mid);
		Build(rs,mid+1,R-1);
		pushup(x);
	}
	void Build(int &x,vector <int> &v){
		if (v.empty())
			return;
		int n=0;
		for (auto i : v)
			id[++n]=new_node(i);
		Build(x,1,n);
	}
	void Ins(int &x,int v){
		pair <int,int> p=Split(x,_Rank(x,v));
		x=Merge(p.fi,Merge(new_node(v),p.se));
	}
	void Remove(int x){
		if (x)
			Remove(ls),Remove(rs),cly::Recover(x);
	}
	#undef ls
	#undef rs
}
int Test,n;
LL ans=0;
vector <int> e[N];
int fa[N][20],depth[N],len[N];
int LCA(int x,int y){
	if (depth[x]<depth[y])
		swap(x,y);
	Fod(i,16,0)
		if (depth[x]-(1<<i)>=depth[y])
			x=fa[x][i];
	if (x==y)
		return x;
	Fod(i,16,0)
		if (fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
int Dis(int x,int y){
	return len[x]+len[y]-2*len[LCA(x,y)];
}
int r[N];
namespace dt{
	int fa[N],size[N],mxs[N],depth[N];
	int rt[N],rtf[N];
	int node_cnt=0;
	void Init(){
		clr(fa),clr(size),clr(mxs),clr(depth),clr(rt),clr(rtf);
		depth[0]=-1,node_cnt++;
		size[1]=1,mxs[1]=depth[1]=rt[1]=0;
		Treap::Ins(rt[1],0-r[1]);
	}
	int id[N],idc=0;
	void dfs(int x,int pre,int d){
		id[++idc]=x;
		for (auto y : e[x])
			if (y!=pre&&depth[y]>=d)
				dfs(y,x,d);
	}
	int sz[N],msz[N],RT,Size;
	void dfs2(int x,int pre){
		sz[x]=1,msz[x]=0;
		for (auto y : e[x])
			if (y!=pre&&!size[y]){
				dfs2(y,x);
				sz[x]+=sz[y];
				msz[x]=max(msz[x],sz[y]);
			}
		msz[x]=max(msz[x],Size-sz[x]);
		if (!RT||msz[x]<msz[RT])
			RT=x;
	}
	vector <int> id1,id2;
	void dfs3(int x,int pre,int anc){
		sz[x]=1;
		id1.pb(Dis(x,anc)-r[x]);
		if (fa[anc])
			id2.pb(Dis(x,fa[anc])-r[x]);
		for (auto y : e[x])
			if (y!=pre&&!size[y])
				dfs3(y,x,anc),sz[x]+=sz[y];
	}
	void build(int x,int f,int n){
		RT=0,Size=n;
		dfs2(x,0);
		x=RT;
		fa[x]=f,depth[x]=depth[f]+1,size[x]=n,mxs[x]=msz[x];
		id1.clear(),id2.clear();
		dfs3(x,0,x);
		Treap::Build(rt[x],id1);
		Treap::Build(rtf[x],id2);
		for (auto y : e[x])
			if (!size[y])
				build(y,x,sz[y]);
	}
	void Rebuild(int x,int f){
		idc=0;
		dfs(x,0,depth[x]);
		For(_t,1,idc){
			int i=id[_t];
			Treap::Remove(rt[i]),Treap::Remove(rtf[i]);
			depth[i]=size[i]=fa[i]=mxs[i]=rt[i]=rtf[i]=0;
		}
		build(x,f,idc);
	}
	void Ins(int x,int f){
		static vector <int> v;
		fa[x]=f,depth[x]=depth[f]+1;
		rt[x]=rtf[x]=0;
		v.clear();
		for (int i=x;i;i=fa[i]){
			v.pb(i),size[i]++;
			mxs[fa[i]]=max(mxs[fa[i]],size[i]);
			Treap::Ins(rt[i],Dis(i,x)-r[x]);
			if (fa[i])
				Treap::Ins(rtf[i],Dis(fa[i],x)-r[x]);
		}
		node_cnt++;
		reverse(v.begin(),v.end());
		for (auto i : v)
			if (mxs[i]>checkval*size[i]){
				Rebuild(i,fa[i]);
				break;
			}
		if (size[x]>1)
			ans+=Treap::Query(rt[x],r[x])-1;
		for (int i=x,f,d;depth[i];i=f){
			f=fa[i],d=Dis(f,x);
			ans+=Treap::Query(rt[f],r[x]-d)-Treap::Query(rtf[i],r[x]-d);
		}
	}
}
int main(){
	srand(_SEED_);
	Test=read(),n=read();
	For(i,1,n){
		int f=read()^(ans%mod),c=read();
		r[i]=read();
		if (!f){
			dt::Init();
			printf("%lld\n",ans);
			continue;
		}
		e[i].pb(f),e[f].pb(i);
		fa[i][0]=f;
		For(j,1,16)
			fa[i][j]=fa[fa[i][j-1]][j-1];
		depth[i]=depth[f]+1;
		len[i]=len[f]+c;
		dt::Ins(i,f);
		printf("%lld\n",ans);
	}
	return 0;
}

  

标签:rt,fa,55,void,紫荆花,depth,WC2014,int,size
来源: https://www.cnblogs.com/zhouzhendong/p/UOJ55.html