洛谷 P9869 [NOIP2023] 三值逻辑 题解
Solution
- 模拟程序,容易发现每个点最后的取值都是定值或一个点的初始值(可能是该值取反)。
- 最后是定值的点可以确定初始值,最后取值由该点决定的点也可以确定取值。求出这些取值,答案加上取之为 U 的点的个数。
- 即第
个点最后的取值是 的初始值, 表示是否取反,那么连一条 权值为 的无向边。若 的取值是定值,忽略。 - 枚举每个连通块,可以发现确定连通块内一个点的初始值即可确定连通块内其他点的初始值。BFS 判断是否存在权值为奇数的环,若存在说明整个连通块取值为 U,答案加上连通块大小。
时间复杂度
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现