【洛谷P4172】[WC2006]水管局长【LCT】

传送门

Solution

查询一条最大边权最小的路径,且要支持删边,我们可以想到用(LCT)维护最小生成树,查询(x,y)时就(split(x,y)),然后输出这条链上最大的边权即可。

维护边权我们可以将每条边都看作一个新的点(x),从原边的(2)个端点向(x)连边,将(x)的点权置为原边权,这样我们就只需要维护链上的最大点权,这就很好做了。

但是删边对最小生成树的影响让我们觉得有些棘手,考虑离线下来倒着处理,改删边为加边,注意到每加入一条边(()(u,v,w))就会导致最小生成树上出现一个环,根据最小生成树的基本性质,我们此时只要删掉换上的边权最大的边就能得到新的最小生成树。

于是我们直接查询最小生成树上(u,v)链上的最大值,将它与(w)比大小,如果(w)更大,直接跳过,否则将边权最大的那条边(cut)掉并(link)新边即可。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,mx[N],val[N],pos[N],ch[N][2],fa[N],rev[N];
inline bool which(int x){return ch[fa[x]][1]==x;}
inline void pushup(int x){
	mx[x]=val[x];pos[x]=x;
	if(mx[ch[x][0]]>mx[x]) mx[x]=mx[ch[x][0]],pos[x]=pos[ch[x][0]];
	if(mx[ch[x][1]]>mx[x]) mx[x]=mx[ch[x][1]],pos[x]=pos[ch[x][1]];
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline void rever(int x){
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}
inline void pushdown(int x){
	if(!rev[x]) return ;
	if(ch[x][0]) rever(ch[x][0]);
	if(ch[x][1]) rever(ch[x][1]);
	rev[x]=0;
}
inline void Rotate(int x){
	int y=fa[x],z=fa[y],wx=which(x),wy=which(y);
	if(!isroot(y)) ch[z][wy]=x;fa[x]=z;
	ch[y][wx]=ch[x][wx^1];
	if(ch[y][wx]) fa[ch[y][wx]]=y;
	ch[x][wx^1]=y;fa[y]=x;
	pushup(y);
}
int stk[N],top;
inline void Splay(int x){
	int now=x;
	stk[top=1]=now;
	while(!isroot(now)) now=fa[now],stk[++top]=now;
	while(top) pushdown(stk[top--]);
	while(!isroot(x)){
		int y=fa[x];
		if(!isroot(y)){
			if(which(x)==which(y)) Rotate(y);
			else Rotate(x);
		}Rotate(x);
	}
	pushup(x); 
} 
inline void access(int x){
	for(int last=0;x;last=x,x=fa[x])
		Splay(x),ch[x][1]=last,pushup(x);
}
inline void makeroot(int x){
	access(x);Splay(x);
	rever(x);
}
inline int findroot(int x){
	access(x);Splay(x);
	while(ch[x][0]) pushdown(x),x=ch[x][0];
	Splay(x);
	return x;
}
inline void split(int x,int y){
	makeroot(x);access(y);
	Splay(y);
}
inline void link(int x,int y){
	makeroot(x);
	fa[x]=y;
}
inline void cut(int x,int y){
	split(x,y);
	fa[x]=ch[y][0]=0;
	pushup(y);
}
struct node{
	int u,v,w;
}e[N],p[N]; 
int m,q,cnt,sum,op[N],x[N],y[N],pd[1010][1010],g[1010][1010],pa[N],ans[N];
pair<int,int> wh[N];
struct cmp{
	inline bool operator ()(node x,node y){return x.w<y.w;}
};
inline int find(int x){return pa[x]==x?x:pa[x]=find(pa[x]);}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	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);
		g[e[i].u][e[i].v]=e[i].w;
	}
	for(int i=1;i<=q;++i){
		scanf("%d%d%d",&op[i],&x[i],&y[i]);
		if(op[i]==1) continue;
		if(x[i]>y[i]) swap(x[i],y[i]);
		if(g[x[i]][y[i]]>0) pd[x[i]][y[i]]=1;
	}
	for(int i=1;i<=m;++i){
		if(pd[e[i].u][e[i].v]) continue;
		p[++cnt]=e[i];
	}
	sort(p+1,p+cnt+1,cmp());
	sum=n;
	for(int i=1;i<=n;++i) pa[i]=i;
	int tot=0;
	for(int i=1;i<=cnt;++i){
		int fx=find(p[i].u),fy=find(p[i].v);
		if(fx==fy) continue;
		pa[fx]=fy;++tot;
		++sum;val[sum]=p[i].w;
		wh[sum]=make_pair(p[i].u,p[i].v);
		link(p[i].u,sum);link(p[i].v,sum);
		if(tot==n-1) break;
	}
	for(int i=q;i>=1;--i){
		if(op[i]==1){
			split(x[i],y[i]);
			ans[i]=mx[y[i]];
		}		
		else{
			int t=g[x[i]][y[i]];
			split(x[i],y[i]);
			if(mx[y[i]]<t) continue;
			int p=pos[y[i]];
			cut(wh[p].first,p);
			cut(wh[p].second,p);
			++sum;val[sum]=t;wh[sum]=make_pair(x[i],y[i]);
			link(x[i],sum);link(y[i],sum); 
		}
	}
	for(int i=1;i<=q;++i)
		if(op[i]==1)
			printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/tqxboomzero/p/14243279.html