Kruskal 重构树

这个还是基于Kruskal最小生成树算法.
我们正常跑最小生成树,把两个点放到并查集中.
但是这个里面我们把边换成一个点权等于边权的点,然后让他与两个点链接起来.
最后就形成了Kruskal 重构树.
写这个是因为考场上的这个题,链接
考场上思路只到最小生成树,然后想不下去了,感觉与并查集维护没差别.
现在发现当时我脑子有多昏了,虽然说现在还是挺昏的.
这个题考虑要求,它说[l,r]全部相通.所以放上一个最小生成树,边权是边的编号,这个好想.
然后对这个树遍历一遍,用st表维护父亲信息与最值.
这个时候我们预处理出来l与l+1的LCA信息,因为我们区间都连续,所以直接把每个l,l+1的信息维护出来.
对这些信息放到一个新的ST表中或者线段树中维护即可.
至于Kruskal 重构树,它的意义在于打最小生成树时会发现,st表维护的信息是不固定的,你要在dfs中把上面的边值给该点.
将边权赋给st表,也不算很麻烦吧,但Kruskal 重构树更直观些.(其实没有大差别)

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define qr qr()
#define ps push_back
#define fi first
#define se second
#define pa pair<int,int>
#define ve vector
using namespace std;
const int N=4e5+200;
int dep[N],st[N<<1][24],mx[N<<1][24],ans[N],val[N<<1];
ve <int> e[N];
inline ll qr{
	ll x=0;char ch=getchar();bool f=0;
	while(ch>57||ch<48)f=(ch=='-')?1:0,ch=getchar();
	while(ch>=48&&ch<=57)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
struct tr{
	int l,r,mx;
}t[N<<2];
inline void add(int f,int t){
	e[f].ps(t);
	e[t].ps(f);
}
void dfs(int u,int fa,int dp){
	dep[u]=dp;
	for(int i=1;i<=20;++i){
		st[u][i]=st[st[u][i-1]][i-1];
		mx[u][i]=max(mx[st[u][i-1]][i-1],mx[u][i-1]);
	}
	// cout<<u<<endl;
	// for(int i=0;i<=4;++i)
	// 	cout<<mx[u][i]<<' ';
	// cout<<endl;
	for(auto v:e[u]){
		if(v==fa)continue;
		st[v][0]=u;
		mx[v][0]=val[u];
		dfs(v,u,dp+1);
	}
}
inline int lca(int a,int b){
	if(dep[a]<dep[b])swap(a,b);
	int mxx=0;
	for(int i=20;i>=0;--i){
		if(dep[st[a][i]]>=dep[b])
			mxx=max(mxx,mx[a][i]),a=st[a][i];
	}if(a==b)return mxx;
	for(int i=20;i>=0;--i)
		if(st[a][i]!=st[b][i])
			mxx=max({mxx,mx[a][i],mx[b][i]}),a=st[a][i],b=st[b][i];
	return mxx;
}
void build(int rt,int l,int r){
	t[rt].l=l;t[rt].r=r;
	if(l==r){
		t[rt].mx=ans[l];
		return;
	}int md=(l+r)>>1;
	build(rt<<1,l,md);
	build(rt<<1|1,md+1,r);
	t[rt].mx=max(t[rt<<1].mx,t[rt<<1|1].mx);
}
int n,m,q,tot,fa[N];
int find(int a){
	return(a==fa[a])?a:fa[a]=find(fa[a]);
}
int ask(int rt,int l,int r){
	if(l>r)return 0;
	if(t[rt].l>=l&&t[rt].r<=r)return t[rt].mx;
	int mxx=0;
	if(t[rt<<1].r>=l)mxx=ask(rt<<1,l,r);
	if(t[rt<<1].r<r)mxx=max(mxx,ask(rt<<1|1,l,r));
	return mxx;
}
inline void merge(int f,int t){
	f=find(f),t=find(t);
	fa[t]=fa[f];
}
void init(){
	n=qr;m=qr;q=qr;
	tot=n;
	for(int i=1;i<=n;++i)fa[i]=i;
	for(int i=1;i<=m;++i){
		int f=qr,t=qr;
		if(find(f)!=find(t)){
			merge(f,t);
			add(f,++tot);
			add(tot,t);
			val[tot]=i;
		}
	}
	dfs(1,0,1);
	for(int i=1;i<n;++i)
		ans[i]=lca(i,i+1);
	build(1,1,n);
	while(q--){
		int a=qr,b=qr;
		cout<<ask(1,a,b-1)<<endl;
	}
}
int main(){
	




	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);





	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	init();
	return 0;
}
posted @ 2024-07-26 20:00  SLS-wwppcc  阅读(8)  评论(0)    收藏  举报