1. 程式人生 > >【BZOJ 3123】 [Sdoi2013]森林 主席樹啟發式合並

【BZOJ 3123】 [Sdoi2013]森林 主席樹啟發式合並

name clas tree lca 部分 print 一切都 getch fine

我們直接按父子關系建主席樹,然後記錄倍增方便以後求LCA,同時用並查集維護根節點,而且還要記錄根節點對應的size,用來對其啟發式合並,然後每當我們合並的時候我們都要暴力拆小的一部分重復以上部分,總時間復雜度為O(n*log),因為每個的節點只會作為小的部分合並,因此他所在的一小部分至少變大2倍,對於每一個節點他作為被合並方最多log次,因此其復雜度為O(n*log),而這個是絕對跑不滿還差很多的,我們視他為無常數就好了,當然這一切都是建立在無拆分操作的基礎之上,只要有了拆分啟發式合並的復雜度就是暴力了。

#include <cstdio>
#include <cstring>
#include 
<iostream> #include <algorithm> #define MAXN 80001 using namespace std; inline int read(){ register int sum=0;register char ch=getchar(); while(ch<0||ch>9)ch=getchar(); while(ch>=0&&ch<=9)sum=(sum<<1)+(sum<<3)+ch-0,ch=getchar(); return sum; }
int n,m,T,fa[MAXN],size[MAXN],f[MAXN][20]; struct Via{ int to,next; }c[MAXN<<1]; int head[MAXN],t; struct Seg_Tree{ Seg_Tree *ch[2]; int size; }*root[MAXN],*null; int pos[MAXN],a[MAXN],deep[MAXN]; int Hash[MAXN],len; bool v[MAXN]; //*********************Define********************// inline int
find(int x){ return x==fa[x]?x:(fa[x]=find(fa[x])); } inline void Unit_to_(int x,int y){ fa[find(x)]=find(y); } //*******************Union_Find_Sets*************// inline void add(int x,int y){ c[++t].to=y,c[t].next=head[x],head[x]=t; } //********************Maintain_Tree**************// int comp(const int x,const int y){ return a[x]<a[y]; } inline void HASH(){ sort(pos+1,pos+n+1,comp); for(register int i=1;i<=n;i++) if(i==1||a[pos[i]]!=a[pos[i-1]])Hash[++len]=a[pos[i]],a[pos[i]]=len; else a[pos[i]]=len; } //********************Hash**********************// void ins(Seg_Tree *&p,Seg_Tree *last,int l,int r,int key){ p=new Seg_Tree,*p=*last,++p->size;if(l==r)return; if(key<=((l+r)>>1))ins(p->ch[0],last->ch[0],l,((l+r)>>1),key); else ins(p->ch[1],last->ch[1],((l+r)>>1)+1,r,key); } void Dfs_Build(int x,int Fa){ deep[x]=deep[Fa]+1;v[x]=1; for(register int i=1;i<20;i++)f[x][i]=f[f[x][i-1]][i-1]; ins(root[x],root[Fa],1,len,a[x]); for(register int i=head[x];i;i=c[i].next) if(c[i].to!=Fa) f[c[i].to][0]=x,Dfs_Build(c[i].to,x); } int query(Seg_Tree *A1,Seg_Tree *A2,Seg_Tree *B1,Seg_Tree *B2,int l,int r,int k){ if(l==r)return l;register int sum=A1->ch[0]->size-A2->ch[0]->size+B1->ch[0]->size-B2->ch[0]->size; if(sum>=k)return query(A1->ch[0],A2->ch[0],B1->ch[0],B2->ch[0],l,((l+r)>>1),k); else return query(A1->ch[1],A2->ch[1],B1->ch[1],B2->ch[1],((l+r)>>1)+1,r,k-sum); } void Del(Seg_Tree *p,Seg_Tree *last){ if(p==last)return; Del(p->ch[0],last->ch[0]),Del(p->ch[1],last->ch[1]); delete p; } void Delete(int x,int fa){ for(register int i=head[x];i;i=c[i].next) if(c[i].to!=fa)Delete(c[i].to,x); Del(root[x],root[fa]),root[x]=null; } //********************Seg_Tree******************// inline int Lca(int x,int y){ if(deep[x]<deep[y])x^=y^=x^=y; register int k=deep[x]-deep[y]; for(register int i=0;(1<<i)<=k;i++) if(k&(1<<i)) x=f[x][i]; if(x==y)return x; for(register 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]; } //*********************LCA*********************// inline void Init(){ scanf("%*d"),n=read(),m=read(),T=read(); null=new Seg_Tree,null->ch[0]=null->ch[1]=null,null->size=0,root[0]=null; for(register int i=1;i<=n;i++)a[i]=read(),pos[i]=i,root[i]=null,size[i]=1,fa[i]=i;HASH(); for(register int i=1,x,y;i<=m;i++)x=read(),y=read(),add(x,y),add(y,x),size[find(y)]+=size[find(x)],Unit_to_(x,y); for(register int i=1;i<=n;i++)if(!v[i])Dfs_Build(find(i),0); } inline void Work(){ register int x,y,k,lca,ans=0;register char s[1]; while(T--){ scanf("%s",s); if(s[0]==Q){ x=read()^ans,y=read()^ans,k=read()^ans,lca=Lca(x,y); printf("%d\n",(ans=Hash[query(root[x],root[lca],root[y],root[f[lca][0]],1,len,k)])); }else{ x=read()^ans,y=read()^ans;if(size[find(x)]>size[find(y)])x^=y^=x^=y; Delete(find(x),0),size[find(y)]+=size[find(x)],Unit_to_(x,y); f[x][0]=y,add(x,y),add(y,x),Dfs_Build(x,y); } } } //*********************Main********************// int main(){ Init(); Work(); return 0; }

【BZOJ 3123】 [Sdoi2013]森林 主席樹啟發式合並