Solution
- 模拟程序,容易发现每个点最后的取值都是定值或一个点的初始值(可能是该值取反)。
- 最后是定值的点可以确定初始值,最后取值由该点决定的点也可以确定取值。求出这些取值,答案加上取之为 U 的点的个数。
- 即第 \(i\) 个点最后的取值是 \(to_i\) 的初始值,\(sg_i\) 表示是否取反,那么连一条 \((i,to)\) 权值为 \(sg_i\) 的无向边。若 \(i\) 的取值是定值,忽略。
- 枚举每个连通块,可以发现确定连通块内一个点的初始值即可确定连通块内其他点的初始值。BFS 判断是否存在权值为奇数的环,若存在说明整个连通块取值为 U,答案加上连通块大小。
时间复杂度 \(\mathcal{O}(n+m)\)。
Code
#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
using namespace std;
namespace Milkcat {
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 2e5 + 5;
struct Graph {
struct edge { LL from, to, w, next; } e[N]; LL cnt, head[N];
void ins(LL u, LL v, LL w = 0) { e[++ cnt] = {u, v, w, head[u]}, head[u] = cnt; }
void clear() { memset(head, 0, sizeof head), cnt = 0; }
#define FEG(u, v, W, G, i) \
for (LL i = G.head[u], v = G.e[i].to, W = G.e[i].w; i; i = G.e[i].next, v = G.e[i].to, W = G.e[i].w)
} G, E;
LL n, m, u, v, ans, to[N], val[N], sgn[N], dis[N], vis[N];
char ch;
int XOR(int u, int sg) { return (u == 2 ? u : (u ^ sg)); }
void dfs(int u, int w) {
val[u] = w;
FEG(u, v, sg, G, i) dfs(v, XOR(w, sg));
}
int main() {
cin >> n >> m;
REP(i, 1, n) to[i] = i;
REP(i, 1, m) {
cin >> ch;
if (ch == '+') cin >> u >> v, to[u] = to[v], sgn[u] = sgn[v];
if (ch == '-') cin >> u >> v, to[u] = to[v], sgn[u] = sgn[v] ^ 1;
if (ch == 'T') cin >> u, to[u] = -1, sgn[u] = 0;
if (ch == 'F') cin >> u, to[u] = 0, sgn[u] = 0;
if (ch == 'U') cin >> u, to[u] = -2, sgn[u] = 0;
}
REP(i, 1, n)
if (to[i] > 0) G.ins(to[i], i, sgn[i]);
memset(val, -1, sizeof val);
REP(i, 1, n)
if (to[i] < 1) dfs(i, -to[i]);
REP(i, 1, n) {
if (val[i] >= 0) ans += (val[i] == 2), vis[i] = 1;
else E.ins(i, to[i], sgn[i]), E.ins(to[i], i, sgn[i]);
}
auto BFS = [&](int s) {
queue<int> q; vector<int> st; bool success = 1;
dis[s] = 0, q.push(s), st.push_back(s);
while (!q.empty()) {
int u = q.front(); q.pop();
FEG(u, v, w, E, i) {
if (dis[v] == -1) dis[v] = dis[u] ^ w, q.push(v), st.push_back(v);
else if (dis[v] != (dis[u] ^ w)) success = 0;
}
}
for (int u : st) dis[u] = -1, vis[u] = 1;
if (!success) ans += st.size();
};
memset(dis, -1, sizeof dis);
REP(i, 1, n)
if (!vis[i]) BFS(i);
cout << ans << '\n';
G.clear(), E.clear(), ans = 0;
memset(to, 0, sizeof to);
memset(sgn, 0, sizeof sgn);
memset(vis, 0, sizeof vis);
return 0;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int C, T = 1; cin >> C >> T;
while (T --) Milkcat::main();
return 0;
}
标签:P9869,ch,洛谷,int,题解,LL,sgn,REP,dis
From: https://www.cnblogs.com/Milkcatqwq/p/17975414