zoukankan      html  css  js  c++  java
  • 洛谷 P4219 [BJOI2014]大融合【LCT】

    传送门
    LCT 维护子树信息,对于每个节点,另开一个变量 (f_2) 记录其虚子树的总和,那么它的子树和就是 (f[u]=f[ls]+f[rs]+val[u]+f_2[u])
    这个维护操作就比较讲究了,在原树的形态发生变化的时候一定要注意即时修改 (f_2)
    (access):将实边与虚边互换,那么 (f_2[u]=f_2[u]-f[t]+f[rs])
    (link):为一个点 (y) 增加虚子树 (x) ,所以 (f_2[y]+=f[x])
    其他操作均不需要单独的改值,因为并没有修改树的形态,(cut) 虽然改了树的形态但是也可以通过 pushup 自己更新到正确的值。

    • 注意对节点的值进行更改的时候一定要先将它转到 splay 的根,这样它现在的值才是正确的值,切记切记。
    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    
    struct LinkCutTree{
    	#define ls(x) (ch[x][0])
    	#define rs(x) (ch[x][1])
    	int fa[N],ch[N][2],siz[N],rev[N],siz2[N];
    	int ident(int p,int f){return ch[f][1]==p;}
    	void connect(int p,int f,int k){ch[f][k]=p;fa[p]=f;}
    	bool ntroot(int p){return ls(fa[p])==p||rs(fa[p])==p;}
    	void pushup(int p){siz[p]=siz[ls(p)]+siz[rs(p)]+1+siz2[p];}
    	void Rev(int p){swap(ls(p),rs(p));rev[p]^=1;}
    	void pushdw(int p){if(rev[p]) Rev(ls(p)),Rev(rs(p));rev[p]=0;}
    	void rotate(int p){
    		int f=fa[p],ff=fa[f],k=ident(p,f);
    		connect(ch[p][k^1],f,k);
    		fa[p]=ff;
    		if(ntroot(f)) ch[ff][ident(f,ff)]=p;
    		connect(f,p,k^1);
    		pushup(f),pushup(p);
    	}
    	void pushall(int p){if(ntroot(p))pushall(fa[p]);pushdw(p);}
    	void splay(int p){
    		pushall(p);
    		while(ntroot(p)){
    			int f=fa[p],ff=fa[f];
    			if(ntroot(f)) ident(p,f)^ident(f,ff)?rotate(p):rotate(f);
    			rotate(p);
    		}
    	}
    	void access(int p){for(int t=0;p;p=fa[t=p])splay(p),siz2[p]+=siz[rs(p)]-siz[t],rs(p)=t,pushup(p);}
    	void makert(int p){access(p);splay(p);Rev(p);}
    	int findrt(int p){access(p);splay(p);while(ls(p))p=ls(p),pushdw(p);splay(p);return p;}
    	void split(int p,int q){makert(p);access(q);splay(q);}
    	void link(int p,int q){makert(p);makert(q);fa[p]=q;siz2[q]+=siz[p];pushup(q);}
    	void cut(int p,int q){split(p,q);if(ls(q)==p&&!rs(p)) fa[p]=ls(q)=0;pushup(p);pushup(q);}
    	int getsize(int p){makert(p);return siz[p];}
    }lct;
    
    int n,q;
    
    int main(){
    	scanf("%d%d",&n,&q);
    	while(q--){
    		char opt[5];int x,y;
    		scanf("%s%d%d",opt,&x,&y);
    		if(opt[0]=='A') lct.link(x,y);
    		else{
    			lct.cut(x,y);
    			int siz1=lct.getsize(x),siz2=lct.getsize(y);
    			printf("%lld
    ",1ll*siz1*siz2);
    			lct.link(x,y);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Go jaegerde 应用【logger+gorm+grpc+http】
    Go gRPC 调试工具
    iris和xxl-job整合
    Go Grpc部署到 k8s【端口共享】
    rocketmq事务 go 采用rocketmq-client-go的实现
    Go Grpc部署到 k8s【负载均衡】
    ubuntu18安装Kubernetes 1.20.5
    k8s Python API
    go nacos服务发现
    k8s集群日志收集ELK和graylog
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12717550.html
Copyright © 2011-2022 走看看