Figure Fixing

思路

首先,我们只考虑变化前后离目标的差距,所以我们可以设点权 \(a_i=t_i-v_i\),那么就变成了如何让所有点权变为 \(0\)

然后,我们发现哇,这么多点,一点也不好处理,由于这道题是个连通图,所以我们直接强行给它缩到两个点去处理,那么如果点权和为奇数,缩到两个点后,肯定一个奇一个偶所以肯定无解。

那么为了强行缩到两个点去处理,我们最理想的图便是二分图,因为二分图简单,因为是个连通图,所以对于一边的两个点,我们必然可以通过一个路径是的一个加 \(x\),一个减 \(x\),如下图:

对于 \(1,3\) 点,我么可以让 \(1,2\) 同时加 \(x\),然后让 \(2,3\) 同时减 \(x\),从而达到一边两点做到一个加 \(x\) 一个减 \(y\),从而达到让所有点缩到两个点,所以判别两边的点权和是否相同即可(补充:这个图还解释了一个事情,对于三个相连的点,而且可以通过删边变成图中的形状,那么我们可以将一个点缩了)。

那么如果不是二分图,所以图里面必然有奇环,我们可以将一个点先拆了,然后奇环便成了偶环,然后直接二分图启动!

啊不是,这个不用二分图,由于原来的一个点被我们拆成了两个点,所以我们可以变换这两个点的点权,从而他们的差是可以为任意一个数(当然,和和的奇偶性相同),依照二分图解法(嗨嗨嗨,又是它),我们呢可以将其余的分为两边,然后做减法,那么根具二分图做法,我们需要的是这个差为 \(0\),那么如果不是 \(0\),就需要这个被拆除来的数补位,由于总和为奇数的情况肯定无解,所以这个差与那个补位的点的差值奇偶性相同,所以补位的点肯定能完美的完成它的职责。

code

点击查看代码
#include <iostream>
#include <vector>
#define int long long

using namespace std;

const int MaxN = 2e5 + 10;

int col[MaxN], a[MaxN], v[MaxN], t, n, m, ans;
vector<int> g[MaxN];

bool GO(int x, int c) {
  if (col[x] != -1) {
    return col[x] == c;
  }
  col[x] = c;
  bool res = 1;
  for (int i : g[x]) {
    res &= GO(i, c ^ 1);
  }
  return res;
}

void Solve() {
  cin >> n >> m, ans = 1;
  for (int i = 1; i <= n; i++) {
    vector<int>().swap(g[i]);
    col[i] = -1;
    cin >> v[i];
  }
  int ssum = 0;
  for (int i = 1, t; i <= n; i++) {
    cin >> t;
    a[i] = t - v[i], ssum += a[i];
  }
  for (int i = 1, u, v; i <= m; i++) {
    cin >> u >> v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  ans = !(ssum % 2);
  if (GO(1, 0)) {
    ssum = 0;
    for (int i = 1; i <= n; i++) {
      ssum += (col[i] ? a[i] : -a[i]);
    }
    ans &= !ssum;
  }
  cout << (ans ? "YES" : "NO") << endl;
}

signed main() {
  ios::sync_with_stdio(0), cin.tie(0);
  for (cin >> t; t; t--) {
    Solve();
  }
  return 0;
}
posted @ 2024-06-18 21:03  yabnto  阅读(18)  评论(0)    收藏  举报