CF1971

你说得太对辣發表於2024-06-29

h.

題目條件轉換為,三個值不能有兩個同時為負數。

x,-x 看作 x,\lnot x,條件就變成了 (x \land y) \lor (x \land z) \lor (y \land z)

這個形式顯然是 2-sat,程式碼很好寫。

#include<bits/stdc++.h>
using namespace std;

const int N = 2e6 + 7;

int v[4][N];
vector<int> g[N];
int n;
void add(int a, int b) {
int k1, k2;
if(a > 0) k1 = 1;
else k1 = 0;
if(b > 0) k2 = 1;
else k2 = 0;
a = abs(a);
b = abs(b);
if(k1 && k2){
g[a + n].push_back(b);
g[b + n].push_back(a);
}
else if(!k1 && k2){
g[a].push_back(b);
g[b + n].push_back(a + n);
}
else if(k1 && !k2){
g[a + n].push_back(b + n);
g[b].push_back(a);
}
else if(!k1 && !k2){
g[a].push_back(b + n);
g[b].push_back(a + n);
}
}
int col[N], scc[N], dfn[N], low[N], vis[N];
int scccnt, dfncnt, stk[N], top;
void tarjan(int u) {
low[u] = dfn[u] = ++ dfncnt;
stk[++ top] = u;
vis[u] = 1;
for(auto v : g[u]) {
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
int y;
scccnt ++;
do {
y = stk[top --];
vis[y] = 0;
col[y] = scccnt;
}while(y != u);
}
}

void init() {
for(int i = 0; i <= 2 * n + 10; i ++) {
low[i] = dfn[i] = col[i] = vis[i] = stk[i] = 0;
}
top = 0;
scccnt = 0;
dfncnt = 0;
for(int i = 0; i <= 2 * n; i ++) g[i].clear();
}
void solve() {


cin >> n;

init();
for(int i = 1; i <= 3; i ++) {
for(int j = 1; j <= n; j ++) {
cin >> v[i][j];
}
}
for(int i = 1; i <= n; i ++) {
int x = v[1][i], y = v[2][i], z = v[3][i];
add(x, y);
add(x, z);
add(y, z);
}
for(int i = 1; i <= n * 2; i ++) {
if(!dfn[i]) tarjan(i);
}
for(int i = 1; i <= n; i ++){
if(col[i] == col[i + n]){
cout << "No" << endl;
return ;
}
}
cout << "Yes" << endl;
}
int main() {
int T;
cin >> T;
while(T --) solve();
return 0;
}