UOJ#274 BZOJ4736 【清华集训2016】温暖会指引我们前行

本文介绍了一种利用边权LCT(Link-Cut Tree)解决最大生成树问题的方法,并提供了一份详细的代码实现。文章通过具体示例展示了如何进行节点操作、路径查询等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

边权LCT维护最大生成树即可

据说考场上围绕这题题意还产生了纠纷……不过反正就是最大生成树喽

边权LCT可以看这里

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bitset>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAXN 300010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
int fa[MAXN],son[MAXN][2];
int pe[MAXN],ne[MAXN],fe[MAXN],le[MAXN];
int wrm[MAXN],tim[MAXN],v1[MAXN],v2[MAXN];
int mn[MAXN],sum[MAXN];
bool rev[MAXN];
int st[MAXN],tp;
int f[MAXN];
int n,m;
int FA(int x){
	return f[x]==x?x:f[x]=FA(f[x]);
}
bool cmp(int x,int y){
	return wrm[x]<wrm[y];
}
inline bool ir(int x){
	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
inline void ud(int x){
	fe[x]=son[x][0]?fe[son[x][0]]:pe[x];
	le[x]=son[x][1]?le[son[x][1]]:ne[x];
	sum[x]=mn[x]=0;
	if(son[x][0]){
		sum[x]+=sum[son[x][0]]+tim[pe[x]];
		mn[x]=min(mn[x],min(mn[son[x][0]],pe[x],cmp),cmp);
	}
	if(son[x][1]){
		sum[x]+=sum[son[x][1]]+tim[ne[x]];
		mn[x]=min(mn[x],min(mn[son[x][1]],ne[x],cmp),cmp);
	}
}
inline void torev(int x){
	if(!x){
		return ;
	}
	swap(son[x][0],son[x][1]);
	swap(fe[x],le[x]);
	swap(pe[x],ne[x]);
	rev[x]^=1;
}
inline void pd(int x){
	if(rev[x]){
		torev(son[x][0]);
		torev(son[x][1]);
		rev[x]=0;
	}
}
inline void cot(int x,int y,bool z){
	if(x){
		fa[x]=y;
	}
	if(y){
		son[y][z]=x;
	}
}
inline void rot(int x,bool z){
	int xx=fa[x],xxx=fa[xx];
	cot(son[x][z],xx,z^1);
	if(ir(xx)){
		fa[x]=xxx;
	}else{
		cot(x,xxx,son[xxx][1]==xx);
	}
	cot(xx,x,z);
	ud(xx);
}
inline void apd(int x){
	int i;
	st[++tp]=x;
	for(i=x;!ir(i);i=fa[i]){
		st[++tp]=fa[i];
	}
	for(;tp;tp--){
		pd(st[tp]);
	}
}
void splay(int x){
	apd(x);
	while(!ir(x)){
		int xx=fa[x],xxx=fa[xx];
		if(ir(xx)){
			rot(x,son[xx][0]==x);
		}else{
			bool z=son[xxx][0]==xx;
			if(son[xx][z]==x){
				rot(x,z^1);
				rot(x,z);
			}else{
				rot(xx,z);
				rot(x,z);
			}
		}
	}
	ud(x);
}
inline void acs(int x){
	int t=0;
	while(x){
		splay(x);
		son[x][1]=t;
		ne[x]=fe[t];
		ud(x);
		t=x;
		x=fa[x];
	}
}
inline void reboot(int x){
	acs(x);
	splay(x);
	torev(x);
}
inline void link(int x,int y,int z){
	reboot(x);
	fa[x]=y;
	pe[x]=z;
	ud(x);
}
inline void cut(int x,int y){
	reboot(x);
	acs(y);
	splay(y);
	son[y][0]=fa[x]=0;
	ne[x]=pe[y]=0;
	ud(x);
	ud(y);
}
int ask(int x,int y){
	reboot(x);
	acs(y);
	splay(y);
	return mn[y];
}
int askans(int x,int y){
	reboot(x);
	acs(y);
	splay(y);
	return sum[y];
}
int main(){
	int i,x,y;
	char o[20];
	wrm[0]=INF;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		f[i]=i;
	}
	while(m--){
		scanf("%s",o);
		if(o[0]=='f'){
			scanf("%d",&x);
			x++;
			scanf("%d%d%d%d",&v1[x],&v2[x],&wrm[x],&tim[x]);
			v1[x]++;
			v2[x]++;
			if(FA(v1[x])!=FA(v2[x])){
				link(v1[x],v2[x],x);
				f[FA(v1[x])]=FA(v2[x ]);
			}else{
				int t=ask(v1[x],v2[x]);
				if(wrm[t]<wrm[x]){
					cut(v1[t],v2[t]);
					link(v1[x],v2[x],x);
				}
			}
		}
		if(o[0]=='m'){
			scanf("%d%d",&x,&y);
			x++;
			y++;
			if(FA(x)!=FA(y)){
				printf("-1\n");
			}else{
				reboot(x);
				acs(y);
				splay(y);
				printf("%d\n",sum[y]);
			}
		}
		if(o[0]=='c'){
			scanf("%d",&x);
			x++;
			reboot(v1[x]);
			acs(v2[x]);
			splay(v2[x]);
			scanf("%d",&tim[x]);
			ud(v2[x]);
		}
	}
	return 0;
}

/*
5 5
find 0 0 1 1 1
find 1 1 2 1 10
find 2 2 3 1 100
find 3 3 4 1 1000
move 0 4

8 19
find 0 0 2 7 2
find 1 2 4 4 4
find 2 4 6 10 1
find 3 6 7 8 6
move 2 7
move 1 6
find 4 2 5 3 4
move 0 5
change 0 12
find 5 4 5 5 10
find 6 2 3 6 9
move 3 5
find 7 0 1 12 1
move 1 6
find 8 1 7 11 100
move 1 6
move 3 7
move 5 6
move 2 2

*/


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值