[luogu6185]序列
对于2操作,如果把这些操作看成边,那么对于某一个连通块内的若干个点,满足权值可以任意分配(证明:归纳,若n个点可以,那么先将新增的点调整好,再对原来n个点重新分配即可),因此可以将原图缩点,并将连通块的和作为新的权值
1操作比较复杂,同样把其当成边连起来,形成一张图(包括自环),然后考虑图中的一个连通块
对这张图,我们可以将操作复杂化:1.对一条长度为奇数的链,两端+1或-1;2.对一条长度为偶数的脸,两端一端+1,一端-1(转化的正确性容易证明)
如果不存在奇环,那么可以二分图染色,之后相当于左右各是一张2操作的完全图,左右之间点权差不变,即需要满足差值与目标差值相同即可
如果存在奇环,那么任意两点之间既存在一条奇数边,又存在一条偶数边,所以相当于既是2操作的完全图,又可以让总点权+2,那么只需要和与目标的和奇偶性相同即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 struct ji{ 5 int nex,to; 6 }edge[N<<1]; 7 vector<int>v[3][N]; 8 int E,t,n,m,p,x,y,head[N],bl[N],a[N],b[N],sum[N]; 9 void add(int x,int y){ 10 edge[E].nex=head[x]; 11 edge[E].to=y; 12 head[x]=E++; 13 } 14 void dfs1(int k){ 15 if (bl[k])return; 16 bl[k]=x; 17 sum[x]+=a[k]-b[k]; 18 for(int i=0;i<v[2][k].size();i++)dfs1(v[2][k][i]); 19 } 20 bool dfs2(int k,int p){ 21 if (bl[k]>=0)return bl[k]==p; 22 if (p)x+=sum[k]; 23 else y+=sum[k]; 24 bl[k]=p; 25 bool flag=1; 26 for(int i=head[k];i!=-1;i=edge[i].nex)flag&=dfs2(edge[i].to,p^1); 27 return flag; 28 } 29 int main(){ 30 scanf("%d",&t); 31 while (t--){ 32 scanf("%d%d",&n,&m); 33 E=0; 34 memset(bl,0,sizeof(bl)); 35 memset(sum,0,sizeof(sum)); 36 memset(head,-1,sizeof(head)); 37 for(int i=1;i<=n;i++)v[1][i].clear(); 38 for(int i=1;i<=n;i++)v[2][i].clear(); 39 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 40 for(int i=1;i<=n;i++)scanf("%d",&b[i]); 41 for(int i=1;i<=m;i++){ 42 scanf("%d%d%d",&p,&x,&y); 43 v[p][x].push_back(y); 44 v[p][y].push_back(x); 45 } 46 x=0; 47 for(int i=1;i<=n;i++) 48 if (!bl[i]){ 49 x++; 50 dfs1(i); 51 } 52 for(int i=1;i<=n;i++) 53 for(int j=0;j<v[1][i].size();j++)add(bl[i],bl[v[1][i][j]]); 54 memset(bl,-1,sizeof(bl)); 55 n=x; 56 bool flag=1; 57 for(int i=1;i<=n;i++) 58 if (bl[i]<0){ 59 x=y=0; 60 p=dfs2(i,0); 61 if (p)flag&=(x==y); 62 else flag&=((x+y)%2==0); 63 } 64 if (flag)printf("YES\n"); 65 else printf("NO\n"); 66 } 67 }