并查集维护染色
Codeforces 776D http://codeforces.com/contest/776/problem/D
实际上是一个黑白图染色问题。但发现只需要用并查集维护当前点与其代表点的颜色关系即可。 如果两个点在同一个连通块,通过比较两个点与代表点的颜色关系即可得出这两个点之间的关系。如果两个点不在同一个连通块,则将两个连通块合并,同时维护颜色关系。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; #define rep(i,a,b) for(int i=a;i<=b;i++) const int N=1e5+5; int a[N],n,m,f[N],g[N],r[N]; int find(int x){ if(f[x]==0)return x; int y=f[x];f[x]=find(y);g[x]^=g[y]; return f[x]; } int main() { cin>>n>>m;rep(i,1,n) scanf("%d",&a[i]),a[i]^=1; rep(i,1,m){ int n,x; scanf("%d",&n);rep(j,1,n){ scanf("%d",&x); if(r[x]==0)r[x]=i;else{ int p=find(r[x]),q=find(i); if(p!=q)f[p]=q,g[p]=g[r[x]]^g[i]^a[x];else { if(g[r[x]]^g[i]!=a[x]){cout<<"NO";return 0;} } } } } cout<<"YES"; }
NOI2001 食物链 https://www.vijos.org/p/1531
黑白染色可以看做一个二元环,而对于n元环的关系也可以通过并查集维护。比如NOI2001食物链。
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=1000001; int i,j,n,m,ans,fa[N],r[N]; int get(int x) { if (x==fa[x]) return x; int y=fa[x];fa[x]=get(fa[x]); r[x]=(r[x]+r[y])%3; return fa[x]; } int main() { scanf("%d%d",&n,&m); for (i=1;i<=n;i++) fa[i]=i; for (i=1;i<=m;i++) { int D,X,Y,fx,fy;scanf("%d%d%d",&D,&X,&Y); if (X>n||Y>n) {ans++;continue;} fx=get(X);fy=get(Y); if (fx!=fy) fa[fy]=fx,r[fy]=(r[X]+D-1-r[Y])%3;else if ((r[Y]-r[X]+3)%3!=D-1) ans++; //printf("%d\n",ans); } printf("%d\n",ans); }