zoukankan      html  css  js  c++  java
  • 并查集重构树

    并查集重构树

    [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;
    }
    
    
  • 相关阅读:
    Grunt 实现浏览器实时刷新
    Node环境搭建
    前端项目三方库管理
    Node项目包管理器
    前端开发利器
    面向对象目录
    Java 面向对象(十四)
    Java 面向对象(十三)
    Java 面向对象(十二)
    Java 面向对象(十)
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13807403.html
Copyright © 2011-2022 走看看