CF1499G Graph Coloring【构造,并查集】
身为一名新时代的好学生,你每天都要按时完成作业。
给定左右分别 \(n_1,n_2\) 个点 \(m\) 条边的无重边的二分图,之后 \(q\) 天,每天的作业可能是:
- \(\texttt{1 u v}\):表示在左边第 \(u\) 个点与右边第 \(v\) 个点连一条边,再求出给边染红蓝色的一种方案,使得 \(\sum_{v\in V}|r(v)-b(v)|\) 尽量小,其中 \(V\) 是点集,\(r(v),b(v)\) 表示与 \(v\) 相连的红/蓝边数量。由于检查作业太麻烦了,你只需要向老师提交 \((\sum_{i\in R}2^i)\bmod 998244353\) 的值。由于方案不唯一,老师不会检查你提交的值是否合法。
- \(\texttt 2\):突击检查作业,你需要提交昨天的完整作业。为了确保你每天都按时完成作业,你提交的方案必须满足你昨天提交的值。
\(n_1,n_2,m,q\le 2\cdot 10^5\),交互式强制在线,保证 \(2\) 操作不超过 \(10\) 个且每个 \(2\) 操作的上一个都是 \(1\) 操作。
如果不带修的话,这事一个我不会的经典问题。
显然一个答案的下界是 \(\sum_{v\in V}\deg(v)\bmod 2\),构造证明也可以取到这个下界。
使用并查集维护边集,维护一堆环/链集合,其中链端点都是度数为奇数的点,然后相间染色即为合法方案。具体实现上处理深度奇偶性即可。
时间复杂度 \(O(n_1+n_2+(m+q)\alpha(m+q))\)。
#include<bits/stdc++.h>
#define PB emplace_back
#define fi first
#define se second
#define MP make_pair
using namespace std;
typedef pair<int, bool> pib;
const int N = 400003, mod = 998244353;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
} void qmo(int &x){x += x >> 31 & mod;}
int n1, n2, m, q, pw[N], mat[N], siz[N], fa[N], red[N], sum[N], res;
bool val[N];
pib getf(int x){
if(fa[x] == x) return MP(x, false);
auto [f, r] = getf(fa[x]);
return MP(fa[x] = f, val[x] ^= r);
}
void comb(int u, int v){
auto [f1, x] = getf(u);
auto [f2, y] = getf(v);
if(f1 == f2) return;
if(siz[f1] > siz[f2]){swap(f1, f2); swap(x, y);}
siz[f2] += siz[f1]; fa[f1] = f2;
qmo(sum[f2] += sum[f1] - mod);
qmo(red[f2] += red[f1] - mod);
if(val[f1] = (x == y)){
int _ = sum[f1] - (red[f1]<<1);
if(_ >= 0) _ -= mod; if(_ < -mod) _ += mod;
qmo(res += _); qmo(red[f2] += _);
}
}
void add(int u, int v, int k){
sum[k] = pw[k+1]; siz[k] = 1; fa[k] = k;
if(~mat[u]){comb(mat[u], k); mat[u] = -1;} else mat[u] = k;
if(~mat[v]){comb(mat[v], k); mat[v] = -1;} else mat[v] = k;
}
int main(){
read(n1); read(n2); read(m); pw[0] = 1;
for(int i = 1;i < (N<<1);++ i) qmo(pw[i] = (pw[i-1]<<1) - mod);
memset(mat, -1, sizeof mat);
for(int i = 0, u, v;i < m;++ i){
read(u); read(v); add(u-1, v+n1-1, i);
} read(q);
while(q --){
int op; read(op);
if(op == 1){
int u, v; read(u); read(v);
add(u-1, v+n1-1, m++);
printf("%d\n", res); fflush(stdout);
} else {
vector<int> ans;
for(int i = 0;i < m;++ i)
if(getf(i).se) ans.PB(i+1);
printf("%ld", ans.size());
for(int u : ans) printf(" %d", u);
putchar('\n'); fflush(stdout);
}
}
}