zoukankan      html  css  js  c++  java
  • 【树】动态树 LCT

    动态树(LCT)

    学习笔记: Yang Zhe QTREE解法的一些研究 , OIWiki

    时间复杂度: (mathcal{O(nlogn)})

    前置知识: splay, 树链剖分

    理解

    • 可以简单把 LCT 理解成用一些 Splay 来维护动态的树链剖分,一期实现动态树上的区间操作。

    • 对于每条实链,建一个 Splay 来维护整个链的区间。

    • 每棵 Splay 维护原树中的一条路径,且中序遍历这颗 Splay 得到的点序列,从前到后对应原树 从上到下的一条路径。

    • 在 LCT 中,每棵 Splay 的根节点的父亲节点指向原树中 这条链 的父亲节点。

    变量声明

    • ch[N][2] 左右儿子
    • f[N] ⽗亲指向
    • sum[N] 路径权值和
    • val[N] 点权
    • tag[N] 翻转标记

    函数声明

    Splay 系函数

    1. Get(x) 获取 是父亲的哪个儿子。
    2. Splay(x) 通过和 Rotate 操作联动实现把 旋转到当前 Splay 的根。
    3. Rotate(x) 将 向上旋转一层的操作。

    新操作

    1. Access(x) 把从根到 的所有点放在⼀条实链里,使根到 成为一条实路径,并且在同一棵 Splay 里。 只有此操作是必须实现的,其他操作视题目而实现。
    2. IsRoot(x) 判断 是否是所在树的根。
    3. Update(x)Access 操作之后,递归地从上到下 Pushdown 更新信息。
    4. MakeRoot(x) 使 点成为其所在树的根。
    5. Link(x, y) 在 两点间连一条边。
    6. Cut(x, y) 把 两点间边删掉。
    7. Find(x) 找到 所在树的根节点编号。
    8. Fix(x, v) 修改 的点权为 。
    9. Split(x, y) 提取出 间的路径,方便做区间操作。

    模板

    //LCT
    struct LCT{
        int ch[maxn][2],f[maxn],tag[maxn],val[maxn],sum[maxn];
        inline int getch(int x){return ch[f[x]][1]==x;}
        inline int isroot(int x){return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;}
        inline void pushdown(int p){
            if(tag[p]){
                if(ch[p][0])swap(ch[ch[p][0]][0],ch[ch[p][0]][1]),tag[ch[p][0]]^=1;
                if(ch[p][1])swap(ch[ch[p][1]][0],ch[ch[p][1]][1]),tag[ch[p][1]]^=1;
                tag[p]=0;
            }
        }
        inline void pushup(int x){
            if(ch[x][0])pushdown(ch[x][0]);
            if(ch[x][1])pushdown(ch[x][1]);
            sum[x]=(val[x]+sum[ch[x][0]]+sum[ch[x][1]])%mod;
        }
        void update(int p){
            if (!isroot(p))update(f[p]);
            pushdown(p);
        }
        inline void rotate(int x){
            int y=f[x],z=f[y],k=getch(x);
            if (!isroot(y))ch[z][ch[z][1]==y]=x;
            ch[y][k]=ch[x][!k],f[ch[x][!k]]=y;
            ch[x][!k]=y,f[y]=x,f[x]=z;
            pushup(x),pushup(y);
        }
        //Splay(x) 通过和 Rotate 操作联动实现把 x 旋转到当前 Splay 的根
        inline void splay(int x){
            update(x);
            for(int fa;fa=f[x],!isroot(x);rotate(x)){
                if(!isroot(fa))rotate(getch(fa)==getch(x)?fa:x);
            }
            pushup(x);
        }
        //Access(x) 把从根到 x 的所有点放在一条实链里,使根到 x 成为一条实路径,并且在同一棵Splay里
        //返回值y 则此时x到当前根的路径恰好构成一个Splay,且该Splay的根为y
        inline int access(int x){
            int p;
            for(p=0;x;p=x,x=f[x]){
                splay(x);ch[x][1]=p;pushup(x);
            }
            return p;
        }
        //MakeRoot(x) 使x点成为其所在树的根
        inline void makeroot(int p){
            access(p);splay(p);
            swap(ch[p][0],ch[p][1]);
            tag[p]^=1;
        }
        //在x,y两点间连一条边
        inline void link(int x,int p){
            makeroot(x);
            splay(x);
            f[x]=p;
        }
        // split 拿出一颗Splay 维护x到y的路径
        inline void split(int x,int y){
            makeroot(x);access(y);splay(y);
        }
        //把x,y两点间的边删掉
        inline void cut(int x,int p){
            split(x,p);
            if(ch[p][0]==x&&!ch[x][1])ch[p][0]=f[x]=val[x]=0;
        }
        //如果有 Find(x)==Find(y),则说明x,y两点在一棵树上,相互连通
        inline int find(int p){
            access(p);splay(p);
            while(ch[p][0])p=ch[p][0];
            splay(p);
            return p;
        }
        inline int lca(int x,int y){access(x);return access(y);}
        void print(int x) {
            if (!x) return;
            pushdown(x);
            printf("(");
            print(ch[x][0]);
            printf(")%d[", x);
            print(ch[x][1]);
            printf("]");
        }
    }st;
    
  • 相关阅读:
    Vue+Element-UI+jQuery+Layer+Camera+Easing的简单应用
    Vue(vue-cli脚手架)中使用layer.js做非模态弹窗(二)
    unicable
    grep 搜索目录时,怎样排除某些目录?
    Mali Midgard架构解析
    如何从GFP确定最后申请的内存来自哪个zone?
    内存申请 GFP_KERNEL GFP_ATOMIC
    Linux内核中的page migration和compaction机制简介
    IOVA/IOMMU
    memory zone spanned/present/managed区别
  • 原文地址:https://www.cnblogs.com/kkkek/p/13637151.html
Copyright © 2011-2022 走看看