zoukankan      html  css  js  c++  java
  • [模板] 动态树/LCT

    简介

    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
    ",i,fa(i),ls(i),rs(i),tree[i].sum,tree[i].rv);
    	}
    }lct;
    
    //init
    rep(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);
    
  • 相关阅读:
    关于 “支持“XXXDBContext”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库” 的解决办法
    ASP.NET MVC 添加Model并连接到本地数据库
    C#中的if if...和if-else if
    Git和Github的使用教程
    JavaEE和Tomcat环境
    将windows系统新建的文本文档默认编码为UTF-8
    WIN10缺少.NET Framework3.5解决办法
    上传图片预览设置src不显示
    IOS new Date() 时间转换失败问题以及其他问题
    是否支持css3
  • 原文地址:https://www.cnblogs.com/ubospica/p/10270646.html
Copyright © 2011-2022 走看看