• [笔记] 带权并查集与种类并查集


    作为一个要考试的人,还不会并查集,简直了。。。


    带权并查集

    先上一道题:P2024 [NOI2001]食物链

    相信大家都会吧QwQ

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() {R x=0,f=1;
    	register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    	do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
    } const int N=50010;
    int n,m,fa[N],d[N],ans;
    inline int getf(int x) {
    	if(x==fa[x]) return x;
    	R f=getf(fa[x]); d[x]=(d[x]+d[fa[x]])%3; return fa[x]=f;
    }
    inline void merge(int u,int v,int w) {
    	R uf=getf(u),vf=getf(v);
    	fa[uf]=vf; d[uf]=(d[v]-d[u]+3+w)%3;
    }
    inline void main() {
    	n=g(),m=g(); for(R i=1;i<=n;++i) fa[i]=i;
    	for(R i=1,op,u,v;i<=m;++i) { op=g(),u=g(),v=g();
    		if(u>n||v>n) {++ans; continue;}
    		if(op==2&&u==v) {++ans; continue;}
    		if(op&1) { if(getf(u)!=getf(v)) merge(u,v,0);
    			else if(d[u]!=d[v]) ++ans;
    		} else {
    			if(getf(u)!=getf(v)) merge(u,v,1);
    			else if((d[u]-d[v]+3)%3!=1) ++ans;
    		}
    	} printf("%d
    ",ans);
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    大致这样想

    所以此时的边感觉是有方向的。

    再来看一道别的题:P4079 [SDOI2016]齿轮

    还是类似刚才的思路,将齿差比作为边权,若在同一个连通块就ck一下。

    注意齿差比的正反(反过来就是倒数)

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
    	register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    	do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
    } const int N=10010; const long double eps=1E-6;
    int T,n,m,t,fa[N]; 
    long double d[N]; bool flg;
    inline bool ck0(long double x) {return x<eps&&x>-eps;}
    inline int getf(int x) { 
    	if(fa[x]==x) return x;
    	R f=getf(fa[x]); d[x]*=d[fa[x]]; return fa[x]=f;
    }
    inline bool merge(int u,int v,int up,int dn) {
    	R uf=getf(u),vf=getf(v); if(uf==vf) return !(ck0(d[v]/d[u]-1.0*dn/up));
    	fa[vf]=uf,d[vf]*=d[u]/d[v]*dn/up; return false;
    }
    inline void main() { 
    	T=g(); while(T--) { printf("Case #%d: ",++t); 
    		n=g(),m=g(); for(R i=1;i<=n;++i) fa[i]=i;
    		for(R i=1;i<=n;++i) d[i]=1.0;
    		for(R i=1,u,v,up,dn;i<=m;++i) { 
    			u=g(),v=g(),up=g(),dn=g();
    			if(!flg&&merge(u,v,up,dn)) puts("No"),flg=true;
    		} if(!flg) puts("Yes"); flg=false;
    	} 
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    再来一道:托派和斯派

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
      register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
      do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
    } const int N=5e5+10;
    int n,m,ans1;
    int c[2][N],fa[N],d[N],h[N];
    inline int getf(int x) {
      if(x==fa[x]) return x;
      R f=getf(fa[x]); d[x]^=d[fa[x]]; return fa[x]=f;
    }
    inline void merge(int u,int v,int w) {
      if(h[u]<h[v]) swap(u,v);
      else h[u]+=h[u]==h[v];
      ans1-=(max(c[0][u],c[1][u])+max(c[0][v],c[1][v]));
      c[0][u]+=c[0^w][v],c[1][u]+=c[1^w][v],fa[v]=u,d[v]=w; 
      ans1+=max(c[0][u],c[1][u]);
    }
    inline void main() {
      ans1=n=g(),m=g();
      for(R i=1;i<=n;++i) c[0][i]=1;
      for(R i=1;i<=n;++i) fa[i]=i;
      for(R i=1,u,v,uf,vf;i<=m;++i) {
        u=g(),v=g(),uf=getf(u),vf=getf(v);
        if(vf==uf) printf("0 %d
    ",ans1);
        else merge(uf,vf,d[u]^d[v]^1),printf("1 %d
    ",ans1);
      }
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    种类并查集

    还是这道:P2024 [NOI2001]食物链

    相信大家也都会吧QwQ

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
    	register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    	do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
    } const int N=50010;
    int n,m,ans;
    int fa[N*3];
    inline int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
    inline void merge(int u,int v) {u=getf(u),v=getf(v),fa[u]=v;}
    inline void main() {
    	n=g(),m=g(); for(R i=1;i<=3*n;++i) fa[i]=i;
    	for(R i=1,op,u,v;i<=m;++i) {
    		op=g(),u=g(),v=g();
    		if(u>n||v>n) {++ans; continue;}
    		if(op==2&&u==v) {++ans; continue;} 
    		if(op&1) {
    			if(getf(u)==getf(v+n)||getf(u+n)==getf(v)) {++ans; continue;}//要判正向边和反向边
    			merge(u,v),merge(u+n,v+n),merge(u+2*n,v+2*n);
    		} else {
    			if(getf(u)==getf(v)||getf(u+n)==getf(v)) {++ans; continue;}//要判同类和反向边.刚开始没有判反向边
    			merge(u,v+n),merge(u+n,v+2*n),merge(u+2*n,v);
    		}
    	} printf("%d
    ",ans);
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    我们这里用不同的集合来表示边的有向性。

    ((u,v)) 同类
    ((u,v+n))
    ((u+n,v)) 被吃

    为何要开三个部分:有三种不重叠的动物。

    再来一道:P1525 关押罪犯
    贪心,将边权大的两个点尽量分到不同的集合。当发现在一个集合时,break;

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
    	register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    	do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
    } const int N=20010;
    int n,m;
    int fa[N<<1];
    inline int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
    struct node { int u,v,w; node() {} 
    	node(int _u,int _v,int _w) {u=_u,v=_v,w=_w;}
    	inline bool operator < (const node& that) {return w>that.w;}
    }e[N*5];
    inline void main() {
    	n=g(),m=g(); for(R i=1;i<=2*n;++i) fa[i]=i;
    	for(R i=1,u,v,w;i<=m;++i) 
    		u=g(),v=g(),w=g(),e[i]=node(u,v,w);
    	sort(e+1,e+m+1); for(R i=1;i<=m;++i) {
    		R u=e[i].u,v=e[i].v,w=e[i].w;
    		if(getf(u)==getf(v)) return (void) printf("%d
    ",w);
    		fa[getf(u)]=getf(v+n),fa[getf(u+n)]=getf(v);
    	} puts("0");
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    应该是带权并查集在权值范围不是很大时都可以用种类并查集去写,比如托派和斯派也可以。


    砸实学过的东西
    2019.09.12
    57

  • 相关阅读:
    JS实现 div拖拽 限制在屏幕内
    国际化配置simple_form
    simple_form模板templates erb haml
    git rolify
    rails模板生成bootstrap格式的simple_form的erb文件
    rails生成器生成自定义controller模板
    ubuntu 终端常用命令(转)
    Ruby for Rails笔记
    Java基础
    javascript ybmiaov
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11509900.html
Copyright © 2020-2023  润新知