LCT小結

各種操作

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樹

這坑以後再填吧…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章