1. 程式人生 > >[學習筆記]LCT進階操作 LCT總結——應用篇(附題單)(LCT)

[學習筆記]LCT進階操作 LCT總結——應用篇(附題單)(LCT)

LCT總結——應用篇(附題單)(LCT)

一般都是維護鏈的操作。split即可搞定。

進階操作的話,處理好輔助樹和原樹的關係即可搞定。

其實,最大的區別就是,splay隨便轉,輔助樹形態變了,但是原樹形態不變,makert會讓原樹形態變化

 

LCT維護子樹資訊

真兒子會splay的時候各種變化,但是虛兒子只會在access和link的時候發生變化,其他的時候可以理解為跟著轉。

以處理子樹sz為例,

處理虛邊子樹sz,總sz(包括實邊)兩個

pushup注意下。

access和link注意下。

需要真正找子樹資訊的時候,考慮把x的後繼access掉,把xsplay到根,然後總sz就是子樹sz了。

模板題:

[BJOI2014]大融合

注意查詢x,y的子樹大小的話,makert(x),access(y),splay(y).

其實x,y直接連通,所以現在是一個長度為2的鏈,y是根,x是y的右兒子,然後直接(si[y]+1)*(si[x]+1)即可。(si[x]+1可以換成s[x])

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void
rd(int &x){ char ch;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=1e5+5; int ch[N][2],fa[N],si[N],s[N]; int r[N]; int n,q; bool nrt(int x){
return (ch[fa[x]][0]==x)||(ch[fa[x]][1]==x); } void pushup(int x){ if(x) s[x]=s[ch[x][0]]+s[ch[x][1]]+si[x]+1; } void rev(int x){ swap(ch[x][0],ch[x][1]); r[x]^=1; } void pushdown(int x){ if(r[x]){ rev(ch[x][0]);rev(ch[x][1]); r[x]=0; } } void rotate(int x){ int y=fa[x],d=ch[fa[x]][1]==x; fa[ch[y][d]=ch[x][!d]]=y; if(nrt(y)) ch[fa[x]=fa[y]][ch[fa[y]][1]==y]=x; else fa[x]=fa[y]; ch[fa[y]=x][!d]=y; pushup(y); } int sta[N],top; void splay(int x){ int y=x; sta[++top]=y; while(nrt(y)) y=fa[y],sta[++top]=y; while(top) pushdown(sta[top--]); int z; while(nrt(x)){ y=fa[x],z=fa[y]; if(nrt(y)){ rotate(((ch[z][0]==y)==(ch[y][0]==x))?y:x); } rotate(x); } pushup(x); } void access(int x){ for(int y=0;x;y=x,x=fa[x]){ splay(x); si[x]-=s[y]; si[x]+=s[ch[x][1]]; ch[x][1]=y; pushup(x); } } void makert(int x){ access(x); splay(x); rev(x); } void link(int x,int y){ makert(x); makert(y); si[y]+=s[x]; s[y]+=s[x]; fa[x]=y; pushup(y); } int query(int x,int y){ makert(x);access(y); return (long long)(si[x]+1)*(si[y]+1); } int main(){ rd(n);rd(q); char cc[2]; int x,y; for(reg i=1;i<=n;++i){ si[i]=0;s[i]=1; } while(q--){ scanf("%s",cc+1); rd(x);rd(y); if(cc[1]=='A'){ link(x,y); }else{ printf("%d\n",query(x,y)); } } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2018/12/18 11:13:18 */
大融合

 

LCT維護聯通塊資訊(邊雙聯通分量)

 

LCT維護邊權(常用生成樹)

 

LCT維護子樹資訊

 

LCT維護樹上染色聯通塊