#二分图,并查集#洛谷 6185 [NOI Online #1 提高组] 序列
题目
分析
考虑2操作可以在保证总和不变的情况下任意修改,
如果将2操作所在的连通块用并查集缩点,那么再考虑1操作,
按照1操作建边,如果存在奇环,那么只要这个环的点权和为偶数一定能使 \(a,b\) 相同;
否则一定是一张二分图,黑白染色之后黑点和白点的点权和必须相等。
代码
#include
#include
using namespace std;
const int N=100011; long long s[2],b[N];
struct node{int y,next;}e[N<<1];
int v[N],a[N],f[N],X[N],Y[N],n,m,flag,et,as[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
bool dfs(int x){
bool flag=1; s[v[x]]+=b[x];
for (int i=as[x];i;i=e[i].next)
if (v[e[i].y]==v[x]) flag=0;
else if (v[e[i].y]==-1) v[e[i].y]=v[x]^1,flag&=dfs(e[i].y);
return flag;
}
int main(){
for (int T=iut();T;--T){
n=iut(),m=iut(),X[0]=0,flag=et=1;
for (int i=1;i<=n;++i) a[i]=iut(),f[i]=i,v[i]=-1;
for (int i=1;i<=n;++i) a[i]=iut()-a[i],b[i]=0;
for (int i=1;i<=m;++i){
int opt=iut(),x=iut(),y=iut();
if (opt==2) f[getf(x)]=getf(y);
else X[++X[0]]=x,Y[X[0]]=y;
}
for (int i=1;i<=n;++i) b[getf(i)]+=a[i];
for (int i=1;i<=X[0];++i){
int x=getf(X[i]),y=getf(Y[i]);
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
for (int i=1;i<=n;++i)
if (getf(i)==i&&v[i]==-1){
v[i]=s[0]=s[1]=0;
bool now=dfs(i);
if (now&&(s[0]!=s[1])) {puts("NO"),flag=0; break;}
if (!now&&((s[0]^s[1])&1)) {puts("NO"),flag=0; break;}
}
for (int i=1;i<=n;++i) as[i]=0;
if (flag) puts("YES");
}
return 0;
}