【模板】LCT求最小生成树

参考题目:洛谷P3366


解析:

联赛完后统一更模板题解析。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=5005,M=200005;
int w[N+M],from[N+M],to[N+M];
typedef struct splay_node *point;
struct splay_node{
	point son[2],fa;
	int val,pos,ori;
	bool tag;
	splay_node(){
		son[0]=son[1]=fa=NULL;
		tag=val=pos=0;
	}
	point &lc(){return son[0];}
	point &rc(){return son[1];}
	
	bool isroot(){return !fa||(fa->son[0]!=this&&fa->son[1]!=this);}
	bool which(){return this==fa->son[1];}
	
	void init(){
		son[0]=son[1]=fa=NULL;
		tag=val=pos=0;
	}
	void pushdown(){
		if(tag){
			swap(son[0],son[1]);
			if(son[0])son[0]->tag^=1;
			if(son[1])son[1]->tag^=1;
			tag=0;
		}
	}
	void pushup(){
		pos=ori,val=w[ori];
		if(son[0]&&son[0]->val>val){
			pos=son[0]->pos;
			val=son[0]->val;
		}
		if(son[1]&&son[1]->val>val){
			pos=son[1]->pos;
			val=son[1]->val;
		}
	}
}ttt[N+M];

struct Link_Cut_Tree{
	point tr[N+M];
	Link_Cut_Tree(int n=N+M-1){for(int re i=0;i<=n;++i)tr[i]=&ttt[i],ttt[i].ori=i;}
	
	void Rotate(point now){
		point Fa=now->fa,FA=Fa->fa;
		bool pos=now->which();
		if(FA&&!Fa->isroot())FA->son[Fa->which()]=now;
		Fa->fa=now;
		now->fa=FA;
		Fa->son[pos]=now->son[!pos];
		if(Fa->son[pos])Fa->son[pos]->fa=Fa;
		now->son[!pos]=Fa;
		Fa->pushup();
		now->pushup();
	}
	
	void Splay(point now){
		static point q[N+M];
		static int qn;
		q[qn=1]=now;
		for(point Fa=now;!Fa->isroot();Fa=Fa->fa)q[++qn]=Fa->fa;
		for(int re i=qn;i;--i)q[i]->pushdown();
		for(point Fa=now->fa;!now->isroot();Rotate(now),Fa=now->fa)
		if(!Fa->isroot())Rotate(now->which()==Fa->which()?Fa:now);
	}
	
	void access(point now){
		for(point son=NULL;now;son=now,now=now->fa)
		Splay(now),now->rc()=son,now->pushup();
	}
	
	void makeroot(point now){
		access(now);Splay(now);now->tag^=1;
	}
	
	point findroot(point now){
		access(now),Splay(now);
		while(now->lc())now=now->lc();
		return now;
	}
	
	bool connect(point u,point v){
		makeroot(u);
		return findroot(v)==u;
	}
	bool connect(int u,int v){return connect(tr[u],tr[v]);}
	
	void link(point u,point v){
		makeroot(u),u->fa=v;
	}
	void link(int u,int v){link(tr[u],tr[v]);}
	
	void cut(point u,point v){
		makeroot(u),access(v),Splay(v);
		v->lc()=u->fa=NULL;
	}
	void cut(int u,int v){cut(tr[u],tr[v]);}
	
	int query(point u,point v){
		makeroot(u);
		access(v);
		Splay(v);
		return v->pos;
	}
	int query(int u,int v){return query(tr[u],tr[v]);}
}LCT;

int n,m,ecnt;
int ans,tot;
signed main(){
	ecnt=n=getint();
	m=getint();
	for(ecnt=n+1;ecnt<=n+m;++ecnt){
		int u=from[ecnt]=getint(),v=to[ecnt]=getint();
		w[ecnt]=getint();
		if(!LCT.connect(u,v)){
			LCT.link(u,ecnt);
			LCT.link(v,ecnt);
			ans+=w[ecnt];++tot;
			continue;
		}
		int pos=LCT.query(u,v);
		if(pos<=n||w[pos]<=w[ecnt])continue;
		LCT.cut(from[pos],pos);
		LCT.cut(to[pos],pos);
		ans-=w[pos];
		LCT.link(u,ecnt);
		LCT.link(v,ecnt);
		ans+=w[ecnt];
	}
	if(tot==n-1)cout<<ans;
	else cout<<"orz";
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值