### ZJ g598 另解
首先知道甚麼是二分圖,就是一個圖上可以填兩種顏色,使得每個邊他們兩端的顏色不相同。
題目就是要問是不是二分圖。
先在原本的圖建好顏色,可能有很多個子圖,所以可能很多填法,如分成兩個連通塊: 101/10 和 101/01 都合法,但這沒關係,前面先隨便填一種,然後記得他在哪一塊連通塊(給個編號例如叫 C[i]),接著縮點,把一個連通塊弄成一個點,後面加入新的邊的時候,我們可以用一個 flip 代表有沒有被翻轉 (也就是 0 跟 1 互換),也就是真的顏色,然後第一個點的 flip 一樣不重要,那後面就分成兩個狀況:
1. 兩個點在同個連通塊: 那就直接判斷顏色
2. 兩個點在不同個連通塊: 如果是第一次走到那就調整 flip 讓它們符合關係,如果不是就判斷 `flip[C[now] xor rb[now], flip[C[next]] xor rb[next]` 的關係 (這裡的 now, next 是原始編號、C[i]是所屬連通塊邊號)
時間複雜度 $O(n+m+pk)$
詳細請參考下方程式和註解:
```cpp=
// Author : rickytsung
// Problem : ZJ g598 AC(71ms)
// Date :
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#include <bits/stdc++.h>
#define i64 long long
#define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define pii pair<int, int>
#define f first
#define s second
#define pb(x) push_back(x)
using namespace std;
mt19937 rng(114514);
const int mod1 = 998244353;
int rnd(int l, int r) {
return uniform_int_distribution<int>(l, r)(rng);
}
i64 gcd(i64 a,i64 b){
if (a%b == 0) return(b);
else return(gcd(b, a%b));
}
i64 lcm(i64 a, i64 b){
return a/gcd(a, b) * b;
}
const int maxn = 20005;
vector<int> G[maxn];
vector<pair<int, pair<int,int>>> H[maxn]; // from_com to_com (from to)
int rb[maxn], flip[maxn], C[maxn];
// rb -> color c -> component
bool ans = 0;
void dfs1(int now, int com, int col){
rb[now] = col;
C[now] = com;
for(auto &i:G[now]){
if(rb[i] == -1){
dfs1(i, com, col^1);
}
}
}
void dfs2(int now, int col){
flip[now] = col;
for(auto &i:H[now]){
if(flip[i.f] == -1){ // flip not determined
dfs2(i.f, flip[now]^rb[i.s.f]^rb[i.s.s]^1); // determine other com flip
}
else{ // flip determined
if(flip[now]^rb[i.s.f] == flip[i.f]^rb[i.s.s]){ // no good
ans = 1;
}
}
}
}
int main() {
IOS;
int n, m, u, v, q, k;
cin >> n >> m;
while(m--){
cin >> u >> v;
G[u].pb(v);
G[v].pb(u);
}
memset(rb, -1, sizeof(rb));
for(int i = 0; i <= n; i++){
if(rb[i] == -1){
dfs1(i, i, 0);
}
}
cin >> q >> k;
for(int z = 1; z <= q; z++){
ans = 0;
vector<int> vis_list;
for(int i = 0; i < k; i++){
cin >> u >> v;
if(C[u] == C[v]){ // in the same component
if(rb[u] == rb[v]) ans = 1;
}
else{ //not in the same
vis_list.pb(C[u]); // the node we need to check
vis_list.pb(C[v]);
H[C[u]].push_back({C[v], {u,v}}); // compressed graph
H[C[v]].push_back({C[u], {v,u}});
}
}
for(auto &i : vis_list){
flip[i] = -1; // not vis
}
for(auto &i : vis_list){
if(flip[i] == -1){ // not visited -> visit
dfs2(i, 0);
}
}
for(auto &i : vis_list){
H[i].clear(); // clear the graph array(used part only so time complexity wont f up)
}
if(ans) cout << z << '\n';
}
}
```