各種操作
1.isrt(x) 判斷x是否爲當前輔助樹的根
inline bool isrt(int x){
return R(F(x))!=x&&L(F(x))!=x;
}
2.pushup(x) 合併答案更新
//舉例
inline void pushup(int i){
T[i].mx=max(T[L(i)].mx,T[R(i)].mx);
T[i].mx=max(T[i].mx,T[i].v);
}
3.pushdown(x) x下傳標記
注意要維護左右兩個值時 修改要先pushdown一下,例如BZOJ2243
inline void pushdown(int x){
if(T[x].rev){
T[x].rev=0,T[L(x)].rev^=1,T[R(x)].rev^=1;
Swap(L(x));Swap(R(x));
}
if(T[x].mk){
int mk=T[x].mk;
if(L(x))mark(L(x),mk);
if(R(x))mark(R(x),mk);T[x].mk=0;
}
}
inline void pushdown(int x){//一般
if(T[x].rev){
T[x].rev^=1,T[L(x)].rev^=1,T[R(x)].rev^=1;
swap(L(x),R(x));
}
}
4.Pushdown(x) 將輔助樹中所有祖先標記下傳
void Pushdown(int x){
if(!isrt(x))Pushdown(F(x));
pushdown(x);
}
5.splay(x) 將x旋到輔助樹的根
inline void splay(int x){
Pushdown(x);
while(!isrt(x)){
if(!isrt(F(x)))Rotate(x);
Rotate(x);
}
}
6.access(x) 打通到根節點的輔助樹
inline void access(int x){
for(int i=0;x;i=x,x=F(x))
splay(x),R(x)=i,pushup(x);
}
7.reverse(x) 換根
inline void reverse(int x){
access(x),splay(x),T[x].rev^=1;
}
8.findrt(x) 找到x所在樹的根
inline int findrt(int x){
access(x);splay(x);
while(L(x))x=L(x);
return x;
}
9.link(x,y) 連接x,y
inline int link(int x,int y){
if(findrt(x)==findrt(y))return -1;
reverse(x),F(x)=y;
return 0;
}
10.cut(x,y) 切斷x,y連邊
inline int cut(int x,int y){
if(findrt(x)!=findrt(y)||x==y)return -1;
reverse(x),access(y),splay(y),F(L(y))=0,L(y)=0;pushup(y);
return 0;
}
因爲換根之後x深度小於y深度,將y轉到根後,由於x和y之前有虛邊相連,所以x就在y左子樹
操作大概就這些,具體題目具體分析
子樹信息維護
每個節點的信息分爲虛子樹信息與總信息和
pushup時總信息和等於虛子樹信息+實子樹信息
access時將新實子樹的信息從虛邊信息中刪去,將新虛子樹的信息加進來即可,維護某些最大最小值每個節點開個muitset就好了
舉例
inline void access(int x){
for(int i=0;x;i=x,x=F(x)){
splay(x);
if(R(x))T[x].chain.insert(lmx(R(x))),T[x].path.insert(mx(R(x)));
if(i)T[x].chain.erase(T[x].chain.find(lmx(i))),T[x].path.erase(T[x].path.find(mx(i)));
R(x)=i,pushup(x);
}
}
某些經典的標記
樹上最大連續子段和
inline void pushup(int x){
sz(x)=sz(L(x))+sz(R(x))+1;
S(x)=S(L(x))+S(R(x))+T[x].val;
Ls(x)=max(Ls(L(x)),S(L(x))+T[x].val+Ls(R(x)));
Rs(x)=max(Rs(R(x)),S(R(x))+T[x].val+Rs(L(x)));
ms(x)=max(max(ms(L(x)),ms(R(x))),Rs(L(x))+T[x].val+Ls(R(x)));
}
顏色段數量
inline void pushup(int x){
T[x].sum=T[L(x)].sum+T[R(x)].sum+1;
if(L(x))Lc(x)=Lc(L(x)),T[x].sum-=(T[x].c==Rc(L(x)));else Lc(x)=C(x);
if(R(x))Rc(x)=Rc(R(x)),T[x].sum-=(T[x].c==Lc(R(x)));else Rc(x)=C(x);
}
動態圖維護
最小生成樹
最小生成樹具有環切性質,加入一條邊時刪除環上最大邊即可
最小極差路徑
(沒有找到題…,找到了務必告訴我)
從小到大枚舉最大邊長,然後在這最大邊長下使最小路徑最大,動態最小生成樹即可
二分圖
維護關於刪除時間的最大生成樹
一個奇環的影響僅取決於環上刪除時間最小的邊
對於每個時刻
加入一條邊時
若它爲樹邊直接加
若形成環,則彈出刪除時間最小的邊,若同時爲奇環,則將最小邊加入集合,表示這條邊存在時,圖中總有奇環
(偶環不用加這條邊,因爲若之後加入的邊與這條邊形成了奇環,那麼新邊一定能與其他邊構成奇環)
刪去一條邊時
若爲樹邊直接刪
若在集合中,在集合中刪去
這樣,在每一時刻,若集合大小爲0則圖爲二分圖
ETT+LCT 、AAA樹
這坑以後再填吧…