博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[模板] 动态树/LCT
阅读量:6825 次
发布时间:2019-06-26

本文共 2807 字,大约阅读时间需要 9 分钟。

简介

LCT是一种数据结构, 可以维护树的动态加边, 删边, 维护链上信息(满足结合律), 单次操作时间复杂度 \(O(\log n)\).(不会证)

思想类似树链剖分, 因为splay可以换根, 用splay维护重链, splay的中序遍历即为链按深度从小到大遍历的结果.

操作

注意区分splay和整棵树的区别, splay根和树根的区别.

\(Access(p)\) 操作指的是将p与根放在同一棵splay中.

\(MakeRoot(p)\) 操作指的是将p变为它所在树(而不是splay)的根. 由于维护的是链上信息, 这不会对答案产生影响.

\(FindRoot(p)\) 操作指的是求p所在树(而不是splay)的根.

\(Link(x,y)\) 操作指的是如果p与q不在同一棵树中, 那么连边 \((x,y)\).

\(Cut(x,y)\) 操作指的是如果p与q有边相连, 那么连边 \((x,y)\).

其中, 'p与q有边相连' 等价于同时满足:
- p,q在同一棵树中.
- p,q深度相差1.(splay中p,q中序遍历时相邻)

\(Split(x,y)\) 操作指的是取出 \((x,y)\) 这个链, 并放在一棵splay中.

具体实现见代码.

应用

  • 动态树(代替树链剖分)
  • 动态最小生成树
  • 维护子树信息(AAA树)
  • 维护并查集(e.g. 可持久化并查集)
  • 优化dinic(据tarjan论文)(怕不是会写死)

Code

const int nsz=3e5+50;int n,val[nsz];struct tlct{    struct tnd{int ch[2],fa,sum,rv;}tree[nsz];#define ls(p) tree[p].ch[0]#define rs(p) tree[p].ch[1]#define fa(p) tree[p].fa#define dir(p) (rs(fa(p))==p)    bool isrt(int p){return ls(fa(p))!=p&&rs(fa(p))!=p;}//splay rt    void rev(int p){swap(ls(p),rs(p));tree[p].rv^=1;}    void pu(int p){        tree[p].sum=tree[ls(p)].sum^val[p]^tree[rs(p)].sum;    }    void pd(int p){        if(tree[p].rv==0)return;        if(ls(p))rev(ls(p));        if(rs(p))rev(rs(p));        tree[p].rv=0;    }    void pdt(int p){//push down whole splay; from top to bottom        if(!isrt(p))pdt(fa(p));        pd(p);    }    void rotate(int p){//fa(p) should exist        int x=fa(p),y=fa(x),dir1=dir(p),dir2=dir(x),z=tree[p].ch[dir1^1];        if(!isrt(x))tree[y].ch[dir2]=p;fa(p)=y;        tree[p].ch[dir1^1]=x;fa(x)=p;        tree[x].ch[dir1]=z;if(z)fa(z)=x;        pu(x),pu(p);//can't swap    }    void splay(int p){        pdt(p);        while(!isrt(p)){            if(!isrt(fa(p)))rotate(dir(p)==dir(fa(p))?fa(p):p);            rotate(p);        }    }    void access(int p){        for(int y=0;p;y=p,p=fa(p)){            splay(p),rs(p)=y;            pu(p);        }    }    void makert(int p){//p -> tree rt & splay rt        access(p),splay(p);        rev(p);    }    int findrt(int p){//find tree rt; p -> splay rt        access(p),splay(p);        while(ls(p))pd(p),p=ls(p);        splay(p); //不加会tle... 不知道为什么        return p;    }    bool iscon(int x,int y){return findrt(x)==findrt(y);}    void split(int x,int y){//x -> tree rt; y -> splay rt        makert(x);        access(y);        splay(y);    }    void link(int x,int y){        makert(x);        if(findrt(y)!=x)fa(x)=y;    }    void cut(int x,int y){        split(x,y);        if(fa(x)==y&&rs(x)==0)            fa(x)=ls(y)=0,pu(y);    }    void pr(){        rep(i,1,n)printf("nd=%d fa=%d ls=%d rs=%d sum=%d rv=%d\n",i,fa(i),ls(i),rs(i),tree[i].sum,tree[i].rv);    }}lct;//initrep(i,1,n)tree[i].sum=val[i];//query a chain    lct.split(b,c);    ans=lct.tree[c].sum;//modify one point    lct.makert(b);    val[b]=c;    lct.pu(b);

转载于:https://www.cnblogs.com/ubospica/p/10270646.html

你可能感兴趣的文章
百度地图API示例:使用vue添加删除覆盖物
查看>>
全选 反选案例
查看>>
python的import到底干了啥
查看>>
docker-ce 安装和卸载
查看>>
Sharepoint 弹出消息提示框 .
查看>>
STL——map
查看>>
CTF---密码学入门第三题 奇怪的短信
查看>>
iOS中的物理引擎
查看>>
Visual C# 2015调用SnmpSharpNet库实现简单的SNMP元素查询
查看>>
Beanutils.copyProperties( )用法
查看>>
mysql的使用命令(1)
查看>>
【java 获取路径的方法】
查看>>
Flex 布局教程:实例篇
查看>>
JavaScript学习
查看>>
C#DataTable与Grid的差别
查看>>
18.Git分支管理策略
查看>>
Configuring Network Names
查看>>
01创建数据集
查看>>
vim美化基本配置
查看>>
电机系统标幺值基准值的选取
查看>>