按 2 操作并查集,对每个集合 f2 有 s2f2=∑i∈f2ai−bi,称为小集合。
目的是令所有集合 s2 为 0。
按 1 操作并查集,每个集合由数个小集合组成。
考虑对于集合 f1={f21,f22,f23},对 f21,f22 同加,对f22,f23 同减,可以发现这就是 2 操作(s1={s21+1,s22,s23−1})。因此配合 1 可以奇偶性不变地改变 s2。推广,对于 ∣f1∣≥3,s1mod2=0 有解。
对于集合 f1=f21,f22,考虑到只能同加同减,必须保证 s21=s22。
对于集合 f1=f21,无法操作,必须 s21=0。
此外,若对于操作 1 有 ui=vi,可以随意加减,所在集合必有解。若 ui,vi 所在小集合相同,可以任意改变奇偶性,若所在集合的 s1mod2=0 有解。
代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+10;
int T,n,m,f[N],a[N],b[N],slf[N];
LL s2[N],s1[N];
struct mdf{int op,x,y;}q[N];
vector<int>p[N];
bool t[N];
int getfa(int x){return x==f[x]?x:(f[x]=getfa(f[x]));}
void merge(int x,int y){x=getfa(x);y=getfa(y);f[x]=y;}
signed main(){
// freopen("P6185_11.in","r",stdin);
//freopen(".out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
for(int i=1;i<=m;i++)scanf("%d%d%d",&q[i].op,&q[i].x,&q[i].y);
for(int i=1;i<=n;i++)f[i]=i,slf[i]=s1[i]=s2[i]=0,p[i].clear(),t[i]=0;
for(int i=1;i<=m;i++)if(q[i].op==2)merge(q[i].x,q[i].y);
for(int i=1;i<=n;i++)s2[getfa(i)]+=a[i]-b[i],t[i]=(i==getfa(i));
for(int i=1;i<=m;i++)if(q[i].op==1){
if(q[i].x==q[i].y)slf[getfa(q[i].x)]=max(slf[getfa(q[i].x)],2);
else if(getfa(q[i].x)==getfa(q[i].y))slf[getfa(q[i].x)]=max(slf[getfa(q[i].x)],1);
}
for(int i=1;i<=m;i++)if(q[i].op==1)merge(q[i].x,q[i].y);
for(int i=1;i<=n;i++)if(t[i])slf[getfa(i)]=max(slf[getfa(i)],slf[i]);
for(int i=1;i<=n;i++)if(t[i])s1[getfa(i)]+=s2[i],p[getfa(i)].push_back(s2[i]);
// for(int i=1;i<=n;i++)printf("%d %d %d,",s1[getfa(i)],p[i].size(),slf[i]);puts("");
bool ans=1;
for(int i=1;i<=n;i++)if(i==getfa(i))
ans=(ans&&
(p[i].size()>2&&s1[i]%2==0||
p[i].size()==2&&p[i][0]==p[i][1]||
p[i].size()==1&&!s1[i]||
slf[i]==2||
slf[i]==1&&s1[i]%2==0));
puts(ans?"YES":"NO");
}
return 0;
}