题目链接:https://codeforces.com/contest/1537/problem/F
题目大意:
n个点的无向图,共有m条边。,每个点有一个初始权重
,有一个目标权重
。可以进行任意次操作,每次操作可以选择一条边
,分别把点i和点j的权重加上任意整数k。
求是否可以通过操作,把每个点的权重变为目标权重。
题解:
每次操作总权重增加。所以总权重的奇偶性不变。若初始总权重和目标总权重的奇偶不同则一定不能。
除此之外我们继续分析:
若图为二分图,则每次操作二分图两边都会加上相同的权重,所以若二分图两边的总权重需要改变的值不同,则一定不行。
剩下二分图两边总权重需要改变的值相同的情况如何处理呢?
如图,我们可以尝试先用边E1让V1达到目标,然后用E2让V2达到目标,用E3让V3达到目标,由于左右两边总权重需要改变的值相同,这时V4一定也满足条件。因此对于这种结构的二分图在这种情况下一定可以达到目标。而我们可以把所有二分图,删除多余边构造为这种结构。所以所有二分图在两边总权重需要改变的量相同的情况下,都可以构造出满足条件的方案。
若图不是二分图如何处理:
如图,我们首先通过E4调整右边的点的总权重,让右边的点的总权重需要改变的量和左边相同,所以非二分图必定可以构造出答案,当然前提是权重的奇偶性需要满足要求。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int nn =210000;
const int inff = 0x3fffffff;
const double eps = 1e-8;
typedef long long LL;
const double pi = acos(-1.0);
const LL mod = 1000000007;
int n,m;
LL u[nn],v[nn];
struct node
{
int en;
int next;
}E[nn*2];
int p[nn];
int num;
void init()
{
memset(p,-1,sizeof(p));
num=0;
}
void add(int st,int en)
{
E[num].en=en;
E[num].next=p[st];
p[st]=num++;
E[num].en=st;
E[num].next=p[en];
p[en]=num++;
}
int vis[nn];
bool solve(int st)
{
queue<int>que;
vis[st]=0;
que.push(st);
LL sum1,sum2;
sum1=sum2=0;
bool twomap=true;
LL usum,vsum;
usum=vsum=0;
while(que.size())
{
int cur=que.front();
que.pop();
usum+=u[cur];
vsum+=v[cur];
if(vis[cur]==0)
sum1+=v[cur]-u[cur];
else
sum2+=v[cur]-u[cur];
for(int i=p[cur];i!=-1;i=E[i].next)
{
int en=E[i].en;
if(vis[en]==-1)
{
vis[en]=vis[cur]^1;
que.push(en);
} else if(vis[en]==vis[cur]) {
twomap=false;
}
}
}
if((usum-vsum)%2!=0)
return false;
if(twomap)
return sum1==sum2;
return true;
}
int main()
{
int t;
cin>>t;
while(t--)
{
init();
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>u[i];
for(int i=1;i<=n;i++)
cin>>v[i];
while(m--)
{
int i,j;
cin>>i>>j;
add(i,j);
}
memset(vis,-1,sizeof(vis));
bool ans=true;
for(int i=1;i<=n;i++)
{
if(vis[i]==-1)
{
if(!solve(i))
{
ans=false;
break;
}
}
}
if(ans)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}