Description
Solution
對於操作二,如果有三個數 有 和 ,那麼可以將 。這意味着如果用並查集將有傳遞性的數加入一個聯通塊中,那麼會有若干個聯通塊,每個聯通塊中任意兩個數都可以進行操作二。那麼如果一個聯通塊中需要加的值與需要減的值相同,那麼一定是合法的。所以把每個聯通塊縮成一個點,點權爲要加的值減去要減的值。
可能有的點權不合法,考慮操作一。如果有 ,那麼可以構成 ,然後 所在的聯通塊中任意一個數可以通過 來白嫖 。如果將操作一對應的點連起來,那麼這三個點構成了奇環,原圖就不是二分圖了,這個可以 bfs 或 dfs 染色求。
不過可能有自環,要特判一下。因爲自環相當於 和 那麼 同樣也可以構成 。
如果是二分圖,那麼兩邊只能同時加一或減一,所以有邊相連的差值相同才能 YES。如果不是二分圖,那麼還可以白嫖加二或減二,所以有邊相連的差值是偶數也是 YES。對於所有沒邊相連的點,點權必須爲 才能是 YES。
時間複雜度 。我沒按秩合併 /kk。
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, INF = 0x3f3f3f3f;
inline int read() {
int x = 0, f = 0; char ch = 0;
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
struct edge{
int to, nxt;
}e[N];
int head[N], tot;
void addedge(int x, int y) {
e[++tot].to = y, e[tot].nxt = head[x], head[x] = tot;
}
int a[N], b[N], f[N], t[N], x[N], y[N], val[N];
int find(int x) {
if (f[x] == x) return x;
return f[x] = find(f[x]);
}
void merge(int x, int y) {
x = find(x), y = find(y);
if (x != y) f[x] = y, val[y] += val[x];
}
int col[N], sum, flg;
void dfs(int x, int c) {
col[x] = c;
if (c) sum += val[x];
else sum -= val[x];
for (int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if (col[y] == -1) dfs(y, c ^ 1);
else if (col[x] == col[y]) flg = 1;
}
}
signed main() {
int T = read();
while (T--) {
memset(col, -1, sizeof(col));
memset(head, 0, sizeof(head)); tot = 0;
int n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) b[i] = read();
for (int i = 1; i <= n; i++) f[i] = i, val[i] = a[i] - b[i];
for (int i = 1; i <= m; i++) {
t[i] = read(), x[i] = read(), y[i] = read();
if (t[i] == 2) merge(x[i], y[i]);
}
for (int i = 1; i <= m; i++)
if (t[i] == 1) addedge(find(x[i]), find(y[i])), addedge(find(y[i]), find(x[i]));
bool ok = 1;
for (int i = 1; i <= n; i++)
if (find(i) == i && col[i] == -1) {
sum = flg = 0;
dfs(i, 0);
for (int j = head[i]; j; j = e[j].nxt)
if (e[j].to == i) {
flg = 1; break;
}
if (head[i] == 0) ok &= (sum == 0);
else if (flg) ok &= (sum % 2 == 0);
else ok &= (sum == 0);
}
if (ok) puts("YES");
else puts("NO");
}
return 0;
}