并查集重构树

并查集重构树

[PA2014]Fiolki

bzoj3712

我们将每瓶药看成一个节点,对于一个操作合并x,y两瓶药就再新建一个节点代表这个操作,左右子节点分别是x,y两瓶药所在子树的根节点。

这样像kruskal重构树一样建出一棵二叉树,也叫并查集重构树。

可以发现对于每一对反应的两瓶药x,y,都是在它们在并查集重构树上的LCA处那个操作时发生反应的。

我们以每个反应的LCA深度为第一关键字,优先度(题目里给的)为第二关键字排序,然后模拟一下即可。

也可以并查集按秩合并

https://blog.csdn.net/The_OIer/article/details/100805617

细节写挂调了40min

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define re register
using namespace std;
typedef long long ll;
const int N=4e5+10;
inline int read() {
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
int n,m,k;
int hd[N],to[N],nxt[N],tot;
inline void add(int x,int y) {
	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
}
int f[N],siz[N],son[N],dep[N];
inline void dfs_son(int x,int fath) {
	f[x]=fath;siz[x]=1;dep[x]=dep[fath]+1;
	for(re int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(y==fath) continue;
		dfs_son(y,x);		
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]]) son[x]=y;
	}
}
int top[N];
inline void dfs_chain(int x,int tp) {
	top[x]=tp;
	if(son[x]) dfs_chain(son[x],tp);
	for(re int i=hd[x];i;i=nxt[i]) {
		if(to[i]!=f[x]&&to[i]!=son[x])
			dfs_chain(to[i],to[i]);
	}
}
inline int LCA(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=f[top[x]];
	}
	return dep[x]<dep[y]?x:y;
} 
int g[N],fa[N];
inline int find(int x) {
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
struct Q{
	int u,v,lca,id;
	Q(){}
	Q(int u_,int v_,int lca_,int id_):u(u_),v(v_),lca(lca_),id(id_){}
//	bool operator < (const Q x) const {
//		return dep[lca]!=dep[x.lca]?dep[lca]>dep[x.lca]:id<x.id;
//	}
}q[500010];
inline bool cmp(Q a,Q b) {
    return dep[a.lca]!=dep[b.lca]?dep[a.lca]>dep[b.lca]:a.id<b.id;
}
ll ans;
int main() {
	n=read();m=read();k=read();
	for(re int i=1;i<=n;i++) g[i]=read();
	for(re int i=1;i<=n+m;i++) fa[i]=i;
	int cnt=n;
	for(re int i=1,a,b;i<=m;i++) {
		a=read();b=read();
		a=find(a),b=find(b);
		fa[a]=fa[b]=++cnt;
		add(cnt,a),add(cnt,b);
	}
	for(re int i=1;i<=n+m;i++)
		if(find(i)==i)
			dfs_son(i,0),dfs_chain(i,i);
	for(re int i=1,a,b;i<=k;i++) {
		a=read();b=read();
		q[i]=Q(a,b,LCA(a,b),i);
	}
	sort(q+1,q+1+k,cmp);
	for(re int i=1,a,b;i<=k;i++) {
		a=q[i].u,b=q[i].v;
		if(find(a)!=find(b)) continue;
		int w=min(g[a],g[b]);
		ans+=2*w;g[a]-=w;g[b]-=w;
	}
	printf("%lld
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/ke-xin/p/13807403.html