并查集的应用
重学并查集,该会的一些操作还是得会。。。
1.路径压缩
2.按秩合并
都略了,一道亲戚两者都用,代码:
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #include<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> #include<bits/stdc++.h> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int maxn=5002; int n,m,k; int f[maxn],r[maxn];//按秩合并 int getfather(int x) { if(x==f[x])return x; return f[x]=getfather(f[x]); } void merge(int x,int y) { if(r[x]>=r[y])f[y]=x,r[x]=max(r[x],r[y]+1); else f[x]=y,r[y]=max(r[x]+1,r[y]); } int main() { //freopen("1.in","r",stdin); n=read();m=read();k=read(); for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++) { int x,y; x=read();y=read(); int xx=getfather(x); int yy=getfather(y); merge(xx,yy); } for(int i=1;i<=k;i++) { int x,y; x=read();y=read(); int xx=getfather(x); int yy=getfather(y); if(xx!=yy)printf("No\n"); else printf("Yes\n"); } return 0; }
听说这样每次getfather都是常数级别的,炒鸡快诶!
然后带边权的并查集,银河英雄传大家都听说过,还是不太好相同的代码丢一波。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<iomanip> #include<algorithm> #include<queue> #include<deque> #include<stack> #include<vector> #include<set> #include<map> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=500002; int n; int f[maxn],d[maxn],sz[maxn]; char ch; int getfather(int x) { if(x==f[x])return x; int root=getfather(f[x]); d[x]+=d[f[x]]; return f[x]=root; } int main() { //freopen("1.in","r",stdin); n=read(); for(int i=1;i<=n;i++)f[i]=i,sz[i]=1; for(int i=1;i<=n;i++) { int x,y; cin>>ch; x=read();y=read(); if(ch=='M') { int xx=getfather(x); int yy=getfather(y); d[xx]=sz[yy];f[xx]=yy; sz[yy]+=sz[xx]; } else { int xx=getfather(x); int yy=getfather(y); if(xx!=yy)printf("-1\n"); else printf("%d\n",abs(d[x]-d[y])-1); } } return 0; }
例题 party game poj 1733 好题
很值得思考的一道题,放到这里啦。。
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #include<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> //#include<bits/stdc++.h> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[500]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int maxn=10002; int n,m; int a[maxn<<1],c[maxn<<1],top=0,k=0; char b[10]; struct wy//闻道玉门犹被遮,应将性命逐轻车 { int l,r,h; }t[maxn<<1]; int f[maxn],d[maxn];//采用带边权的并查集边权为0则x与f[x]奇偶性相同,边权为1则相反 int getfather(int x) { if(x==f[x])return x; int root=getfather(f[x]); d[x]=d[x]^d[f[x]]; return f[x]=root; // } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=m;i++) { t[i].l=read()-1; t[i].r=read(); scanf("%s",b+1); t[i].h=(b[1]=='e'?0:1); a[++top]=t[i].l; a[++top]=t[i].r; } //如果l~r之间区间1为偶数则l-1和r奇偶性相同,为奇数时奇偶性不同. sort(a+1,a+1+top); for(int i=1;i<=top;i++)if(i==1||a[i]!=a[i-1])c[++k]=a[i];//离散 for(int i=1;i<=top;i++)f[i]=i; memset(d,0,sizeof(d)); for(int i=1;i<=m;i++) { int x=lower_bound(c+1,c+1+k,t[i].l)-c; int y=lower_bound(c+1,c+1+k,t[i].r)-c; int xx=getfather(x);int yy=getfather(y); if(xx==yy){if((d[x]^d[y])!=t[i].h){put(i-1);return 0;}} else { f[xx]=yy;d[xx]=d[x]^d[y]^t[i].h; } } put(m); return 0; }
当然还可以用并查集的扩展域写。
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #include<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> //#include<bits/stdc++.h> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[500]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int maxn=10000; int n,m; int a[(maxn<<1)+2],c[(maxn<<1)+2],top=0,k=0; char b[10]; struct wy//闻道玉门犹被遮,应将性命逐轻车 { int l,r,h; }t[(maxn<<1)+2]; int f[(maxn<<1)+2];//采用扩展域并查集 int getfather(int x) { if(x==f[x])return x; return f[x]=getfather(f[x]); } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=m;i++) { t[i].l=read()-1; t[i].r=read(); scanf("%s",b+1); a[++top]=t[i].l; a[++top]=t[i].r; t[i].h=(b[1]=='o')?1:0; } sort(a+1,a+1+top); for(int i=1;i<=top;i++) if(i==1||a[i]!=a[i-1])c[++k]=a[i]; for(int i=1;i<=(maxn<<1);i++)f[i]=i; for(int i=1;i<=m;i++) { int x=lower_bound(c+1,c+1+k,t[i].l)-c; int y=lower_bound(c+1,c+1+k,t[i].r)-c;//代表奇数 int xx=x+maxn;int yy=y+maxn;//代表偶数的 if(t[i].h==0) { int u=getfather(x); int u1=getfather(yy); if(u==u1){put(i-1);return 0;} f[getfather(x)]=getfather(y); f[getfather(xx)]=getfather(yy); } else { int u=getfather(x); int u1=getfather(y); if(u==u1){put(i-1);return 0;} f[getfather(x)]=getfather(yy); f[getfather(y)]=getfather(xx); } } put(m); return 0; }
并查集的扩展域还有食物链等.
关键是第一条命令不好判断,是这样的如果是1的话x要吃的和y在一起或x本身和y要吃的就矛盾了
2的话是x和y在一起或x和y要吃的在一起就矛盾了,两条即可判断了。
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<queue> #include<deque> #include<algorithm> #include<map> #include<set> #include<vector> #include<stack> #include<bits/stdc++.h> #define inf 50000 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void put(int x) { if(x==0){putchar('0');putchar('\n');return;} if(x<0)putchar('-'),x=-x; int num=0;char ch[500]; while(x)ch[++num]=x%10+'0',x/=10; while(num)putchar(ch[num--]); putchar('\n');return; } const int maxn=50002; int n,m; int f[maxn<<2]; int ans=0; int getfather(int x) { if(x==f[x])return x; return f[x]=getfather(f[x]); } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=inf*3;i++)f[i]=i; for(int i=1;i<=m;i++) { int p,x,y; p=read();x=read();y=read();//cout<<p<<endl; if(x>n||y>n){ans++;continue;} //x,y同类,xx,yy是捕食的,xxx,yyy是天敌 int xx=x+inf;int yy=y+inf; int xxx=xx+inf;int yyy=yy+inf; if(p==1) { if(x==y){continue;} if(getfather(x)==getfather(yy)||getfather(xx)==getfather(y)){ans++;continue;} f[getfather(x)]=getfather(y); f[getfather(xx)]=getfather(yy); f[getfather(xxx)]=getfather(yyy); } if(p==2)//x吃y { if(x==y){ans++;continue;} if(getfather(x)==getfather(y)||getfather(x)==getfather(yy)){ans++;continue;} f[getfather(x)]=getfather(yyy); f[getfather(xx)]=getfather(y); f[getfather(xxx)]=getfather(yy); } } put(ans); return 0; }
↖(^ω^)↗