Solution Set - LCT

发布时间 2023-06-12 20:14:29作者: by_chance

A[洛谷P3690]维护一个森林,支持询问路径xor和,连边(已连通则忽略),删边(无边则忽略),改变点权。
B[洛谷P3203]\(n\)个装置编号为\(0,...,n-1\),从\(i\)可以一步跳到\(i+k_i\),支持修改\(k_i\),询问从一个点开始几步跳出\(n-1\)
C[洛谷P2486]给定一棵树,点有颜色,支持路径覆盖,询问路径颜色段数。
D[洛谷P4332]给定一棵树,前\(n\)个点各有三个儿子,叶子结点有权\(0/1\),分支结点的权是其三个儿子权值中较多的一个。支持修改叶子结点权值,询问根节点权值。
E[洛谷P2147]维护一个森林,支持连边,删边,询问连通性。
F[洛谷P2542]维护一个图,支持删边,询问两点间必须边数目。
G[洛谷P4234]求给定无向图的最小差值生成树。(最大权与最小权之差)
H[洛谷P4172]维护一个图,支持删边,询问两点间路径最大权的最小值。
I[洛谷P4180]求给定无向图的严格次小生成树。
J[洛谷P4219]维护一个森林,支持加边,询问经过某条边的简单路径数目。
K[洛谷P4299]维护一个森林,支持加边,询问某棵子树重心编号,询问所有子树重心编号的xor和。


LCT:解决动态树问题的一种数据结构。思想是对树做虚实链剖分(每个点随便选一个实儿子),用Splay维护每条实链。由于Splay的灵活性,可以方便地改变虚边和实边。LCT的核心操作包括:①将一个点到根的路径打通为实链(access);②将一个点设为根(makeroot)。由此可以实现提取路径(split(x,y)=makeroot(x),access(y)),连边(link(x,y)=makeroot(x),fa[x]=y),删边(cut(x,y)=split(x,y),ch[y][0]=fa[x]=0),查找根(findroot)。

A模板。
B连边\(i \to \min(i+k_i,n)\),修改时删边,加边,询问时split(i,n)
C和Splay专题中打标记的思想是类似的。push_up也很好写。
D把儿子中\(1\)的数量看做关键码。将\(0\)改成\(1\)就修改它向上关键码为\(1\)的点,将\(1\)改成\(0\)就修改它向上关键码为\(2\)的点。那么只用实现区间加,维护最深的\(1\)\(2\)
E模板。
F用LCT维护边双。注意只用删边,可以倒过来考虑加边。然后用并查集维护边双。两点间第一次连通就在LCT上正常加边,第二次就合并相应的并查集,并遍历整条路径。

LCT维护边权时,可以考虑拆边。

G按边权排序,从小到大枚举最大边,加入最大边时删去其两端点路径上的最小边,并维护选入的最小边权。
H维护瓶颈生成树。也是倒着加边,加入某条边时尝试替换最大边。
I先求最小生成树,然后尝试加入每条边,取出该链上的最小值或次小值更新答案。如果用LCT写,不用删边,只要询问两点间最小边权和次小边权。

LCT维护子树信息时,采用的思想类似于动态DP,即维护所有虚儿子的信息之和。只用在accesslink中更新。注意link中要写成makeroot(x),makeroot(y),否则会WA。

J模板。询问时可以考虑先删去,然后统计答案,再连回去。
K注意到合并两棵树时,新重心一定在原来的两个重心间的路径上。那么可以提出该路径,在它的Splay上做二分。


点击查看A题代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=3e5+5;
int n,m;map<pii,bool> M;
int fa[N],ch[N][2],val[N],sum[N],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){sum[p]=sum[ls]^sum[rs]^val[p];}
void pushr(int p){tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;if(ls)pushr(ls);if(rs)pushr(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isRoot(int p){return ch[fa[p]][0]!=p&&ch[fa[p]][1]!=p;}
void update(int p){if(!isRoot(p))update(fa[p]);push_down(p);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isRoot(y))ch[z][y==ch[z][1]]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;
	push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int p=fa[x];!isRoot(x);p=fa[x]){
		if(!isRoot(p))rotate(get(p)==get(x)?p:x);
		rotate(x);
	}
}
void Access(int x){
	for(int y=0;x;y=x,x=fa[x])
		splay(x),ch[x][1]=y,push_up(x);
}
int findRoot(int p){
	Access(p);splay(p);
	while(ls)push_down(p),p=ls;
	splay(p);return p;
}
void makeRoot(int p){Access(p);splay(p);pushr(p);}
void split(int x,int y){makeRoot(x);Access(y);splay(y);}
bool link(int x,int y){
	makeRoot(x);
	if(findRoot(y)==x)return false;
	fa[x]=y;return true;
}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
#undef ls
#undef rs
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",val+i);
	for(int op,x,y;m--;){
		scanf("%d%d%d",&op,&x,&y);
		if(op==0)split(x,y),printf("%d\n",sum[y]);
		if(op==1)if(link(x,y))M[pii(x,y)]=M[pii(y,x)]=1;
		if(op==2)if(M[pii(x,y)])cut(x,y),M[pii(x,y)]=M[pii(y,x)]=0;
		if(op==3)splay(x),val[x]=y;
	}
	return 0;
}
点击查看B题代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,a[N];
int fa[N],ch[N][2],sum[N],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){sum[p]=sum[ls]+sum[rs]+1;}
void pushr(int p){tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;if(ls)pushr(ls);if(rs)pushr(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][y==ch[z][1]]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
void makeroot(int p){access(p);splay(p);pushr(p);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
#undef ls
#undef rs
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
		link(i,min(n+1,i+a[i]));
	}
	scanf("%d",&m);
	for(int i=1,op,x;i<=m;i++){
		scanf("%d%d",&op,&x);++x;
		if(op==1)split(x,n+1),printf("%d\n",sum[n+1]-1);
		else cut(x,min(n+1,x+a[x])),scanf("%d",a+x),link(x,min(n+1,x+a[x]));
	}
	return 0;
}
点击查看C题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;char op[3];
int fa[N],ch[N][2],tag[N][2],col[N],lc[N],rc[N],sum[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){
	if(ls)lc[p]=lc[ls];else lc[p]=col[p];
	if(rs)rc[p]=rc[rs];else rc[p]=col[p];
	sum[p]=sum[ls]+sum[rs]+1-(col[p]==rc[ls])-(col[p]==lc[rs]);
}
void make_tag(int p,int op){
	if(op==0)tag[p][0]^=1,swap(ls,rs),swap(lc[p],rc[p]);
	else tag[p][1]=lc[p]=rc[p]=col[p]=op,sum[p]=1;
}
void push_down(int p){
	if(tag[p][0]){tag[p][0]=0;if(ls)make_tag(ls,0);if(rs)make_tag(rs,0);}
	if(tag[p][1]){
		int v=tag[p][1];tag[p][1]=0;
		if(ls)make_tag(ls,v);if(rs)make_tag(rs,v);
	}
}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][y==ch[z][1]]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
void makeroot(int p){access(p);splay(p);make_tag(p,0);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",col+i);
	for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),link(u,v);
	for(int i=1,u,v,w;i<=m;i++){
		scanf("%s",op);
		if(op[0]=='C')scanf("%d%d%d",&u,&v,&w),split(u,v),make_tag(v,w);
		else scanf("%d%d",&u,&v),split(u,v),printf("%d\n",sum[v]);
	}
	return 0;
}
点击查看D题代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,m,ans;
int fa[N*3],ch[N][2],val[N*3],n1[N],n2[N],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){
	if(n1[rs])n1[p]=n1[rs];else if(val[p]!=1)n1[p]=p;else n1[p]=n1[ls];
	if(n2[rs])n2[p]=n2[rs];else if(val[p]!=2)n2[p]=p;else n2[p]=n2[ls];
}
void make_tag(int p,int op){tag[p]+=op;val[p]^=3;swap(n1[p],n2[p]);}
void push_down(int p){
	if(tag[p]){
		if(ls)make_tag(ls,tag[p]);
		if(rs)make_tag(rs,tag[p]);
		tag[p]=0;
	}
}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][y==ch[z][1]]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(x)==get(y)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int head[N*3],nxt[N*3],ver[N*3],tot;
void add(int u,int v){ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void dfs(int u){
	for(int i=head[u],v;i;i=nxt[i])
		dfs(v=ver[i]),val[u]+=val[v]/2;
}
int main(){
	scanf("%d",&n);
	for(int u=1,v1,v2,v3;u<=n;u++){
		scanf("%d%d%d",&v1,&v2,&v3);
		add(u,v1);add(u,v2);add(u,v3);
		fa[v1]=fa[v2]=fa[v3]=u;
	}
	for(int i=n+1,x;i<=3*n+1;i++)scanf("%d",&x),val[i]=2*x;
	dfs(1);ans=val[1]/2;
	scanf("%d",&m);
	for(int i=1,p;i<=m;i++){
		scanf("%d",&p);
		if(val[p]==0){
			val[p]=2;access(p=fa[p]);splay(p);
			if(!n1[p]){make_tag(p,1);ans^=1;}
			else{splay(p=n1[p]);make_tag(rs,1);++val[p];push_up(p);}
		}
		else{
			val[p]=0;access(p=fa[p]);splay(p);
			if(!n2[p]){make_tag(p,-1);ans^=1;}
			else{splay(p=n2[p]);make_tag(rs,-1);--val[p];push_up(p);}
		}
		printf("%d\n",ans);
	}
	return 0;
}
点击查看E题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;char op[15];
int fa[N],ch[N][2],tag[N];
#define ls ch[p][0]
#define rs ch[p][1]
void make_tag(int p){tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;if(ls)make_tag(ls);if(rs)make_tag(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][y==ch[z][1]]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y;}
int findroot(int p){
	access(p);splay(p);
	while(ls)push_down(p),p=ls;
	splay(p);return p;
}
void makeroot(int p){access(p);splay(p);make_tag(p);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;}
bool check(int x,int y){makeroot(x);return findroot(y)==x;}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++){
		scanf("%s",op);
		scanf("%d%d",&u,&v);
		if(op[0]=='C')link(u,v);
		if(op[0]=='D')cut(u,v);
		if(op[0]=='Q')printf(check(u,v)?"Yes\n":"No\n");
	}
	return 0;
}
点击查看F题代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=1e5+5;
int n,m,k,q[N][3];map<pii,int> M;stack<int> ans;
struct Disjoint_Set{
	int fa[N];
	void init(int n){for(int i=1;i<=n;i++)fa[i]=i;}
	int find(int x){return x==fa[x]?x:(fa[x]=find(fa[x]));}
	void Union(int x,int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}
}S;
int fa[N],ch[N][2],tag[N],sum[N];
#define ls ch[p][0]
#define rs ch[p][1]
#define ref S.find(fa[p])
void push_up(int p){sum[p]=sum[ls]+sum[rs]+1;}
void make_tag(int p){if(!p)return;tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;make_tag(ls);make_tag(rs);}}
bool get(int p){return p==ch[ref][1];}
bool isroot(int p){return p!=ch[ref][0]&&p!=ch[ref][1];}
void update(int p){if(!isroot(p))update(ref);push_down(p);}
void rotate(int x){
	x=S.find(x);
	int y=S.find(fa[x]),z=S.find(fa[y]),op=get(x)^1;
	if(!isroot(y))ch[z][get(y)]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int p){
	update(p);
	for(int x=ref;!isroot(p);x=ref){
		if(!isroot(x))rotate(get(x)==get(p)?x:p);
		rotate(p);
	}
}
void access(int p){for(int x=0;p;x=p,p=ref)splay(p),ch[p][1]=x,push_up(p);}
int findroot(int p){
	p=S.find(p);access(p);splay(p);
	while(ls)push_down(p),p=ls;
	splay(p);return p;
}
void makeroot(int p){p=S.find(p);access(p);splay(p);make_tag(p);}
void dfs(int p,int q){
	push_down(p);S.Union(p,q);
	if(ch[p][0])dfs(ch[p][0],q);
	if(ch[p][1])dfs(ch[p][1],q);
}
void link(int x,int y){
	x=S.find(x);y=S.find(y);makeroot(x);
	if(findroot(y)!=x){fa[x]=y;return;}
	dfs(x,x);
}
void split(int x,int y){makeroot(x);access(y);splay(y);}
int query(int x,int y){x=S.find(x);y=S.find(y);split(x,y);return sum[y];}
#undef ls
#undef rs
int main(){
	scanf("%d%d",&n,&m);S.init(n);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);
		if(u>v)swap(u,v);
		M[pii(u,v)]=1;
	}
	for(k=1;scanf("%d",&q[k][0]),q[k][0]!=-1;k++){
		scanf("%d%d",&q[k][1],&q[k][2]);
		if(q[k][1]>q[k][2])swap(q[k][1],q[k][2]);
		if(q[k][0]==0)M[pii(q[k][1],q[k][2])]=0;
	}--k;
	for(auto x:M)if(x.second)link(x.first.first,x.first.second);
	for(int i=k;i>=1;i--){
		if(q[i][0]==0)link(q[i][1],q[i][2]);
		else ans.push(query(q[i][1],q[i][2])-1);
	}
	while(!ans.empty())printf("%d\n",ans.top()),ans.pop();
	return 0;
}
点击查看G题代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int n,m,cnt,ans=1e9,vis[N],l;
struct edge{int u,v,w;}e[N];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
int fa[N],ch[N][2],tag[N],mn[N],val[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){mn[p]=min(min(mn[ls],mn[rs]),val[p]);}
void make_tag(int p){if(!p)return;tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;make_tag(ls);make_tag(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][get(y)]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int findroot(int p){access(p);splay(p);while(ls)push_down(p),p=ls;splay(p);return p;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
int main(){
	memset(mn,0x3f,sizeof(mn));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w),val[i]=i;
	for(int i=m+1;i<=m+n;i++)val[i]=1e9;
	sort(e+1,e+m+1);
	for(int i=1;i<=m;i++){
		if(e[i].u==e[i].v)continue;
		++cnt;vis[i]=1;int x=e[i].u+m,y=e[i].v+m;
		if(findroot(x)==findroot(y)){
			--cnt;split(x,y);int t=mn[y];
			cut(e[t].u+m,t);cut(e[t].v+m,t);vis[t]=0;
		}
		link(x,i);link(y,i);
		while(!vis[l]&&l<=m)++l;
		if(cnt==n-1)ans=min(ans,e[i].w-e[l].w);
	}
	printf("%d\n",ans);
	return 0;
}
点击查看H题代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=2e5+5;
int n,m,k,vis[N];map<pii,int> M;stack<int> ans;
struct edge{int u,v,w;}e[N],q[N];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
int fa[N],ch[N][2],tag[N],val[N],mx[N];
#define ls ch[p][0]
#define rs ch[p][1]
void push_up(int p){mx[p]=max(max(mx[ls],mx[rs]),val[p]);}
void make_tag(int p){if(!p)return;tag[p]^=1;swap(ls,rs);}
void push_down(int p){if(tag[p]){tag[p]=0;make_tag(ls);make_tag(rs);}}
bool get(int p){return p==ch[fa[p]][1];}
bool isroot(int p){return p!=ch[fa[p]][0]&&p!=ch[fa[p]][1];}
void update(int p){if(!isroot(p))update(fa[p]);push_down(p);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][get(y)]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int findroot(int p){access(p);splay(p);while(ls)push_down(p),p=ls;splay(p);return p;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
void link(int s){
	int x=e[s].u+m,y=e[s].v+m;
	if(findroot(x)==findroot(y)){
		split(x,y);int t=mx[y];
		if(e[t].w<=e[s].w)return;
		cut(e[t].u+m,t);cut(e[t].v+m,t);
	}
	link(x,s);link(y,s);
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
		if(e[i].u>e[i].v)swap(e[i].u,e[i].v);
	}
	sort(e+1,e+m+1);
	for(int i=1;i<=m;i++)
		M[pii(e[i].u,e[i].v)]=i,val[i]=i;
	for(int i=1;i<=k;i++){
		scanf("%d%d%d",&q[i].w,&q[i].u,&q[i].v);
		if(q[i].u>q[i].v)swap(q[i].u,q[i].v);
		if(q[i].w==2)vis[M[pii(q[i].u,q[i].v)]]=1;
	}
	for(int i=1;i<=m;i++)if(!vis[i])link(i);
	for(int i=k;i>=1;i--){
		if(q[i].w==2)link(M[pii(q[i].u,q[i].v)]);
		else{
			split(q[i].u+m,q[i].v+m);
			ans.push(e[mx[q[i].v+m]].w);
		}
	}
	while(!ans.empty())printf("%d\n",ans.top()),ans.pop();
	return 0;
}
点击查看I题代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5,INF=1<<30;
int n,m,vis[N],res=INF,cnt;long long ans;
struct edge{int u,v,w;}e[N];
bool operator <(const edge&a,const edge&b){return a.w<b.w;}
int fa[N],ch[N][2],tag[N],val[N],mx[N][2];
#define ls ch[x][0]
#define rs ch[x][1]
void push_up(int x){
	mx[x][0]=max(max(mx[ls][0],mx[rs][0]),val[x]);mx[x][1]=-INF;
	if(mx[ls][0]<mx[x][0])mx[x][1]=max(mx[x][1],mx[ls][0]);
	else mx[x][1]=max(mx[x][1],mx[ls][1]);
	if(mx[rs][0]<mx[x][0])mx[x][1]=max(mx[x][1],mx[rs][0]);
	else mx[x][1]=max(mx[x][1],mx[rs][1]);
	if(val[x]<mx[x][0])mx[x][1]=max(mx[x][1],val[x]);
}
void make_tag(int x){if(!x)return;tag[x]^=1;swap(ls,rs);}
void push_down(int x){if(tag[x]){tag[x]=0;make_tag(ls);make_tag(rs);}}
bool get(int x){return x==ch[fa[x]][1];}
bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
void update(int x){if(!isroot(x))update(fa[x]);push_down(x);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][get(y)]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,push_up(x);}
int findroot(int x){access(x);splay(x);while(ls)push_down(x),x=ls;splay(x);return x;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
#undef ls
#undef rs
void link(int s){
	int x=e[s].u+m,y=e[s].v+m;
	if(findroot(x)==findroot(y))return;
	ans+=e[s].w;vis[s]=1;++cnt;link(x,s);link(y,s);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	sort(e+1,e+m+1);
	for(int i=1;i<=m&&cnt<n-1;i++){val[i]=e[i].w;if(e[i].u!=e[i].v)link(i);}
	for(int i=1;i<=m;i++)if(!vis[i]&&e[i].u!=e[i].v){
		int u=e[i].u+m,v=e[i].v+m;split(u,v);
		if(mx[v][0]==e[i].w)res=min(res,e[i].w-mx[v][1]);
		else res=min(res,e[i].w-mx[v][0]);
	}
	printf("%lld\n",res+ans);
	return 0;
}
点击查看J题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;char op[3];
int fa[N],ch[N][2],tag[N],siz[N],siz2[N];
#define ls ch[x][0]
#define rs ch[x][1]
void push_up(int x){siz[x]=siz[ls]+siz[rs]+1+siz2[x];}
void make_tag(int x){if(!x)return;tag[x]^=1;swap(ls,rs);}
void push_down(int x){if(tag[x]){tag[x]=0;make_tag(ls);make_tag(rs);}}
bool get(int x){return x==ch[fa[x]][1];}
bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
void update(int x){if(!isroot(x))update(fa[x]);push_down(x);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][get(y)]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){
	for(int y=0;x;y=x,x=fa[x]){
		splay(x);siz2[x]+=siz[ch[x][1]]-siz[y];
		ch[x][1]=y;push_up(x);
	}
}
int findroot(int x){access(x);splay(x);while(ls)push_down(x),x=ls;splay(x);return x;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);makeroot(y);fa[x]=y;siz2[y]+=siz[x];}
#undef ls
#undef rs
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++){
		scanf("%s",op);scanf("%d%d",&u,&v);
		if(op[0]=='A')link(u,v);
		else{
			cut(u,v);makeroot(u);makeroot(v);
			printf("%lld\n",1ll*siz[u]*siz[v]);
			link(u,v);
		}
	}
	return 0;
}
点击查看K题代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,ans;char op[5];
struct Disjoint_Set{
	int fa[N],siz[N];
	void init(int n){for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;}
	int find(int x){return x==fa[x]?x:(fa[x]=find(fa[x]));}
	void Union(int x,int y){x=find(x);y=find(y);if(x!=y)fa[x]=y,siz[y]+=siz[x];}
}S;
int fa[N],ch[N][2],tag[N],siz[N],siz2[N];
#define ls ch[x][0]
#define rs ch[x][1]
void push_up(int x){siz[x]=siz[ls]+siz[rs]+1+siz2[x];}
void make_tag(int x){if(!x)return;tag[x]^=1;swap(ls,rs);}
void push_down(int x){if(tag[x]){tag[x]=0;make_tag(ls);make_tag(rs);}}
bool get(int x){return x==ch[fa[x]][1];}
bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
void update(int x){if(!isroot(x))update(fa[x]);push_down(x);}
void rotate(int x){
	int y=fa[x],z=fa[y],op=get(x)^1;
	if(!isroot(y))ch[z][get(y)]=x;
	ch[y][op^1]=ch[x][op];if(ch[x][op])fa[ch[x][op]]=y;
	ch[x][op]=y;fa[y]=x;fa[x]=z;push_up(y);push_up(x);
}
void splay(int x){
	update(x);
	for(int y=fa[x];!isroot(x);y=fa[x]){
		if(!isroot(y))rotate(get(y)==get(x)?y:x);
		rotate(x);
	}
}
void access(int x){
	for(int y=0;x;y=x,x=fa[x]){
		splay(x);siz2[x]+=siz[ch[x][1]]-siz[y];
		ch[x][1]=y;push_up(x);
	}
}
int findroot(int x){access(x);splay(x);while(ls)push_down(x),x=ls;splay(x);return x;}
void makeroot(int x){access(x);splay(x);make_tag(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;push_up(y);}
void link(int x,int y){makeroot(x);makeroot(y);fa[x]=y;siz2[y]+=siz[x];}
int solve(int x){
	int lsum=0,rsum=0,sum=siz[x]>>1,u=1e9,curl,curr;
	while(x){
		push_down(x);
		curl=lsum+siz[ls];curr=rsum+siz[rs];
		if(curl<=sum&&curr<=sum)u=min(u,x);
		if(curl<curr)lsum+=siz[ls]+siz2[x]+1,x=rs;
		else rsum+=siz[rs]+siz2[x]+1,x=ls;
	}
	splay(u);return u;
}
#undef ls
#undef rs
int main(){
	scanf("%d%d",&n,&m);S.init(n);
	for(int i=1;i<=n;i++)ans^=i;
	while(m--){
		scanf("%s",op);
		if(op[0]=='A'){
			int x,y;scanf("%d%d",&x,&y);
			link(x,y);x=S.find(x);y=S.find(y);
			split(x,y);int g=solve(y);
			S.fa[x]=S.fa[y]=S.fa[g]=g;
			ans^=x^y^g;
		}
		if(op[0]=='Q'){int x;scanf("%d",&x);printf("%d\n",S.find(x));}
		if(op[0]=='X')printf("%d\n",ans);
	}
	return 0;
}