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;
}
本文来自博客园,作者:myee,转载请注明原文链接:https://www.cnblogs.com/myee/p/Luogu-solution-p3402.html