[bzoj3123] [SDOI2013]森林 主席樹+啟發式合併+LCT
Description
Input
第一行包含一個正整數testcase,表示當前測試資料的測試點編號。保證1≤testcase≤20。
第二行包含三個整數N,M,T,分別表示節點數、初始邊數、運算元。第三行包含N個非負整數表示 N個節點上的權值。
接下來 M行,每行包含兩個整數x和 y,表示初始的時候,點x和點y 之間有一條無向邊, 接下來 T行,每行描述一個操作,格式為“Q x y k”或者“L x y ”,其含義見題目描述部分。
Output
對於每一個第一類操作,輸出一個非負整數表示答案。
Sample Input
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
Sample Output
2
2
1
4
2
HINT
對於第一個操作 Q 8 7 3,此時 lastans=0,所以真實操作為Q 8^0 7^0 3^0,也即Q 8 7 3。點8到點7的路徑上一共有5個點,其權值為4 1 1 2 4。這些權值中,第三小的為 2,輸出 2,lastans變為2。對於第二個操作 Q 3 5 1 ,此時lastans=2,所以真實操作為Q 3^2 5^2 1^2 ,也即Q 1 7 3。點1到點7的路徑上一共有4個點,其權值為 1 1 2 4 。這些權值中,第三小的為2,輸出2,lastans變為 2。之後的操作類似。
Source
Solution
碼農題
看見只有合併和查詢k大不難想到主席樹+啟發式合併,但是這題還要動態維護lca,所以還要寫個lct。
合併的時候,因為要新加入一個點的權值(小的接到大的的根上,成為大的的直系兒子,所以要加上大的根的權值),所以小的部分整個要dfs一波來更新,啟發式合併可以做到\(O(nlog^2n)\)。
對於動態維護lca,很顯然能用lct維護,不過細節比較多,要注意pushdown的順序以及時機,還有就是找lca就是access(x)之後在access(y)時,找到的最後一個拼接點。找lca的fa時,就在splay裡面按照平衡樹的排序方式找即可。
Code
#include <bits/stdc++.h> using namespace std; #define N 80005 //fastIO namespace IO { const int __S=(1<<21)+5;char __buf[__S],*__H,*__T; inline char getc() { if(__H==__T) __T=(__H=__buf)+fread(__buf,1,__S,stdin); if(__H==__T) return -1;return *__H++; } template <class __I>inline void read(__I &__x) { __x=0;char __c=getc(); while(!isdigit(__c)) __c=getc(); while(isdigit(__c)) __x=__x*10+__c-'0',__c=getc(); } inline void readd(double &__x) { __x=0;double __fg=1.0;char __c=getc(); while(!isdigit(__c)&&__c!='-') __c=getc(); if(__c=='-') __fg=-1.0,__c=getc(); while(isdigit(__c)) __x=__x*10.0+__c-'0',__c=getc(); if(__c!='.'){__x=__x*__fg;return;}else while(!isdigit(__c)) __c=getc(); double __t=1e-1;while(isdigit(__c)) __x=__x+1.0*(__c-'0')*__t,__t=__t*0.1,__c=getc(); __x=__x*__fg; } inline void reads(char *__s,int __x) { char __c=getc();int __tot=__x-1; while(__c<'!'||__c>'~') __c=getc(); while(__c>='!'&&__c<='~') __s[++__tot]=__c,__c=getc(); __s[++__tot]='\0'; } char __obuf[__S],*__oS=__obuf,*__oT=__oS+__S-1,__c,__qu[55];int __qr; inline void flush(){fwrite(__obuf,1,__oS-__obuf,stdout);__oS=__obuf;} inline void putc(char __x){*__oS++ =__x;if(__oS==__oT) flush();} template <class __I>inline void print(__I __x) { if(!__x) putc('0'); if(__x<0) putc('-'),__x=-__x; while(__x) __qu[++__qr]=__x%10+'0',__x/=10; while(__qr) putc(__qu[__qr--]); } inline void prints(const char *__s,const int __x) { int __len=strlen(__s+__x); for(int __i=__x;__i<__len+__x;__i++) putc(__s[__i]); } inline void printd(double __x,int __d) { long long __t=(long long)floor(__x);print(__t);putc('.');__x-=(double)__t; while(__d--) { double __y=__x*10.0;__x*=10.0; int __c=(int)floor(__y); putc(__c+'0');__x-=floor(__y); } } inline void el(){putc('\n');}inline void sp(){putc(' ');} }using namespace IO; //value int T,n,m,q,tot,x,y,z,la,cnt,lim; int a[N*2],b[N*2],rt[N*2],sm[N*400],ls[N*400],rs[N*400],fa[N*2],f[N*2],c[N*2][2],re[N*2],to[N*2*2],he[N*2],ne[N*2*2],sz[N*2]; char o[5]; //basis void add(int x,int y){to[cnt]=y;ne[cnt]=he[x];he[x]=cnt++;} int find(int x){return x==f[x]?x:f[x]=find(f[x]);} //lct bool isrt(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} bool R(int x,int y){return c[x][1]==y;} void dn(int x){if(!re[x]) return;re[x]^=1;re[c[x][0]]^=1;re[c[x][1]]^=1;swap(c[x][0],c[x][1]);} void ro(int x) { int y=fa[x],z=fa[y],a=R(y,x),b=!a;if(!isrt(y)) c[z][R(z,y)]=x; fa[x]=z,fa[y]=x,fa[c[x][b]]=y;c[y][a]=c[x][b],c[x][b]=y; } void U(int x){if(fa[x]) U(fa[x]);dn(x);} void spl(int x){U(x);for(;!isrt(x);ro(x)) if(!isrt(fa[x])) ro(R(fa[x],x)==R(fa[fa[x]],fa[x])?fa[x]:x);} int acs(int x){int g;for(int y=0;x;y=x,x=fa[x]) spl(x),c[x][1]=y,g=x;return g;} void mrt(int x){acs(x);spl(x);re[x]^=1;} void lnk(int x,int y){mrt(x);fa[x]=y;} int lca(int x,int y){acs(x);return acs(y);} //segment void ins(int &y,int x,int l,int r,int v) { y=++tot;sm[y]=sm[x]+1;if(l==r) return;int mid=(l+r)>>1; if(v<=mid) rs[y]=rs[x],ins(ls[y],ls[x],l,mid,v);else ls[y]=ls[x],ins(rs[y],rs[x],mid+1,r,v); } int que(int a,int b,int c,int d,int l,int r,int k) { if(l==r) return l;int mid=(l+r)>>1,g=sm[ls[a]]+sm[ls[b]]-sm[ls[c]]-sm[ls[d]]; return k<=g?que(ls[a],ls[b],ls[c],ls[d],l,mid,k):que(rs[a],rs[b],rs[c],rs[d],mid+1,r,k-g); } //merge void dfs(int x,int fa) { ins(rt[x],rt[fa],1,lim,a[x]); for(int i=he[x],y;~i;i=ne[i]) if((y=to[i])!=fa) dfs(y,x); } void merge(int x,int y) { if(sz[x]<sz[y]) swap(x,y);int a=find(x),b=find(y); sz[a]+=sz[b];f[b]=a;add(x,y);add(y,x);lnk(x,y); } //main int main() { memset(he,-1,sizeof(he));read(T);read(n);read(m);read(q); for(int i=1;i<=n;i++) read(a[i]),f[i]=i,sz[i]=1,b[i]=a[i]; sort(b+1,b+n+1);lim=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n+1,a[i])-b; for(int i=1;i<=n;i++) ins(rt[i],rt[0],1,lim,a[i]); for(int i=1;i<=m;i++) read(x),read(y),merge(x,y); for(int i=1;i<=q;i++) { reads(o,0); if(o[0]=='L') read(x),read(y),x^=la,y^=la,merge(x,y); else { read(x),read(y),read(z);x^=la,y^=la,z^=la;mrt(find(x)); int Lc=lca(x,y),Fa;acs(Lc);spl(Lc);Fa=c[Lc][0]; dn(Fa);while(c[Fa][1]) Fa=c[Fa][1],dn(Fa); print(la=b[que(rt[x],rt[y],rt[Lc],rt[Fa],1,lim,z)]),el(); } } flush(); }