洛谷P4219 [BJOI2014]大融合(LCT,Splay)
阿新 • • 發佈:2018-02-06
else push long 維護 結束 blog htm hup down
LCT維護子樹信息的思路總結與其它問題詳見我的LCT總結
思路分析
動態連邊,LCT題目跑不了了。然而這題又有點奇特的地方。
我們分析一下,查詢操作就是要讓我們求出砍斷這條邊後,x和y各自子樹大小的乘積。
掌握了LCT如何維護虛子樹信息和後,做法就很清晰了。split(x,y)後,輸出x的虛子樹和+1與y的虛子樹和+1的乘積;或者,(以y為根)輸出x的子樹總和與y的子樹總和減去x的子樹總和的乘積。
代碼如下(這次我試著寫了一個單旋"Spaly",好像常數還小不少。。。。。。)
#include<cstdio> #include<cstdlib> #define R register int #define I inline void const int N=100009; int f[N],c[N][2],si[N],s[N]; bool r[N]; #define lc c[x][0] #define rc c[x][1] inline bool nroot(R x){return c[f[x]][0]==x||c[f[x]][1]==x;} I pushup(R x){ s[x]=s[lc]+s[rc]+si[x]+1; } I pushdown(R x){ if(r[x]){ R t=lc;lc=rc;rc=t; r[lc]^=1;r[rc]^=1;r[x]=0; } } I pushall(R x){ if(nroot(x))pushall(f[x]); pushdown(x); } I rotate(R x){ R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k]; if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w; f[w]=y;f[y]=x;f[x]=z; pushup(y); } I splay(R x){//請忽略這個spaly pushall(x); while(nroot(x))rotate(x); pushup(x); } I access(R x){ for(R y=0;x;x=f[y=x]){ splay(x); si[x]+=s[rc]; si[x]-=s[rc=y]; //pushup(x);試著去掉,發現對答案無影響 } } I makeroot(R x){ access(x);splay(x); r[x]^=1; } I split(R x,R y){ makeroot(x); access(y);splay(y); } I link(R x,R y){ split(x,y); si[f[x]=y]+=s[x]; pushup(y); }//LCT模板到此結束 #define G ch=getchar() #define gc G;while(ch<‘-‘)G #define in(z) gc;z=ch&15;G;while(ch>‘-‘)z*=10,z+=ch&15,G; int main(){ register char ch; register bool fl; R n,q,u,v; in(n);in(q); for(R i=1;i<=n;++i)s[i]=1; while(q--){ gc;fl=ch==‘A‘;in(u);in(v); if(fl)link(u,v); else{ split(u,v); printf("%lld\n",(long long)(si[u]+1)*(si[v]+1));//可以換成上面提到的另一種 } } return 0; }
洛谷P4219 [BJOI2014]大融合(LCT,Splay)