Luogu3402

前置芝士:主主树 主席树

【数据删除】。

Solution

有了可持久化线段树后,不难实现可持久化数组。

但是由于毒瘤出题人卡了空间,所以我的 naive 主席树是过不去的!

(悲)

分析其原因,是因为并查集按秩合并时由于要多记一个数组,导致可能要俩主席树,空间炸了。

怎么办?

势能并查集出现了!

给每个节点在最初随机赋予势能,在每次合并时总以势能大的为父亲。

容易证明复杂度期望单次 \(O(\log n)\)

空间减小了大约一半,可以通过。

Code

#include <algorithm>
#include <random>
#include <stdio.h>
#include <vector>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
template<typename T>T power(T base,T index,T mod){return((index<=1)?(index?base:1):(power(base*base%mod,index>>1,mod)*power(base,index&1,mod)))%mod;}
template<typename T>T lowbit(T n){return n&-n;}
template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<typename T>T lcm(T a,T b){return(a!=0||b!=0)?a/gcd(a,b)*b:(T)0;}
template<typename T>T exgcd(T a,T b,T&x,T&y){if(!b)return y=0,x=1,a;T ans=exgcd(b,a%b,y,x);y-=a/b*x;return ans;}
template<typename T,typename len_def>
class Seg
{
	private:
		class node
		{
			public:
				len_def len;T v;node*L,*R;
				node(len_def len=0):len(len),v(),L(NULL),R(NULL){}
				voi build(T*A){if(len==1)v=*A;else(L=new node(len>>1))->build(A),(R=new node(len-(len>>1)))->build(A+(len>>1));}
		};
		std::vector<node*>N,Root;
	public:
		Seg(){N.clear(),Root.clear();}
		voi bzr(){Root.clear();while(!N.empty()){delete N.back();N.pop_back();}}
		voi build(T*A,len_def len){bzr(),N.push_back(new node(len)),Root.push_back(N.back()),Root[0]->build(A);}
		len_def times(){return Root.size();}
		voi add(len_def from,len_def p,T v)
		{
			node*Node=new node,*Last=Root[from];*Node=*Last,Root.push_back(Node);
			while(Node->len>1)(p<(Node->len>>1))?N.push_back(Node->L=new node(Node->len>>1)),*(Node=Node->L)=*(Last=Last->L):(p-=Node->len>>1,N.push_back(Node->R=new node(Node->len-(Node->len>>1))),*(Node=Node->R)=*(Last=Last->R));
			Node->v+=v;
		}
		T find(len_def time,len_def p)
		{
			node*Node=Root[time];
			while(Node->len>1)Node=(p<(Node->len>>1))?Node->L:(p-=Node->len>>1,Node->R);
			return Node->v;
		}
		voi chg(len_def from,len_def p,T v)
		{
			node*Node=new node,*Last=Root[from];*Node=*Last,Root.push_back(Node);
			while(Node->len>1)(p<(Node->len>>1))?N.push_back(Node->L=new node(Node->len>>1)),*(Node=Node->L)=*(Last=Last->L):(p-=Node->len>>1,N.push_back(Node->R=new node(Node->len-(Node->len>>1))),*(Node=Node->R)=*(Last=Last->R));
			Node->v=v;
		}
		voi copy(len_def from){Root.push_back(new node);*Root.back()=*Root[from],N.push_back(Root.back());}
};
Seg<uint,uint>U;uint A[100005],cnt,Time[200005];
uint find(uint n){uint p=U.find(cnt,n);return(p==n)?n:find(p);}
uint High[100005];
int main()
{
	srand(19491001);
	uint n,m,op,p,q;scanf("%u%u",&n,&m);
	for(uint i=0;i<n;i++)A[i]=i,High[i]=rand();
	U.build(A,n);
	for(uint i=1;i<=m;i++)
	{
		scanf("%u",&op);
		if(op==1)
		{
			scanf("%u%u",&p,&q);
			if((p=find(p-1))!=(q=find(q-1)))
			{
				if(High[p]<High[q])std::swap(p,q);
				U.chg(cnt,q,p),cnt=Time[i]=U.times()-1;
			}
			else Time[i]=cnt;
		}
		else if(op==2)scanf("%u",&p),cnt=Time[i]=Time[p];
		else scanf("%u%u",&p,&q),Time[i]=cnt,puts((find(p-1)==find(q-1))?"1":"0");
	}
	return 0;
}
posted @ 2022-02-14 07:23  myee  阅读(45)  评论(0编辑  收藏  举报