intread(){ char u, v; cin >> u >> v; return (u - 48) * 50 + v - 48; }
constint N = 2008;
voideachT(){ int n, l, q; cin >> n >> l >> q;
vector<vector<pair<int, int>>> E(l + 1); for (int i = 1; i <= l; ++i) { vector<int> t(n + 1), cnt(n + 1); for (int j = 1; j <= n; ++j) { t[j] = read(); cnt[t[j]] += 1; } int mul = -1, zero = -1, ok = 1; for (int j = 1; j <= n; ++j) { if (cnt[j] == 2) { if (mul == -1) mul = j; else ok = 0; } if (cnt[j] == 0) { if (zero == -1) zero = j; else ok = 0; } } if (!ok) continue; if (mul == -1) { for (int j = 1; j <= n; ++j) { E[i].emplace_back(j, t[j]); } } elsefor (int j = 1; j <= n; ++j) { if (cnt[t[j]] == 2) { E[i].emplace_back(j, zero); } } }
vector<vector<tuple<int, int, int>>> que(l + 1); for (int i = 0; i < q; ++i) { int a = read(), b = read(), c = read(); que[c].emplace_back(a, b, i); }
vector<int> ans(q); vector<vector<int>> adj(n + 1); DSU dsu(n); for (int c = 0; c <= l; ++c) { for (auto& [u, v] : E[c]) { adj[dsu.find(v)].push_back(dsu.find(u)); }
// Tarjan vector<int> dfn(n + 1), low(n + 1), fa(n + 1); int unix = 0; stack<int> stk; auto dfs = [&](auto&& self, int u) -> void { dfn[u] = low[u] = ++unix; stk.push(u); for (auto& v : adj[u]) { if (!dfn[v]) self(self, v), low[u] = min(low[u], low[v]); elseif (!fa[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { int v; do { v = stk.top(); stk.pop(); fa[v] = u; } while (v != u); } }; for (int u = 1; u <= n; ++u) { if (!dfn[u]) dfs(dfs, u); }
vector<vector<int>> tadj(n + 1); for (int u = 1; u <= n; ++u) { for (auto& v : adj[u]) { if (fa[u] != fa[v]) tadj[fa[u]].push_back(fa[v]); } } for (int u = 1; u <= n; ++u) { dsu.uno(fa[u], u); adj[u] = tadj[u]; adj[u].erase(unique(adj[u].begin(), adj[u].end()), adj[u].end()); }
vector<int> deg(n + 1); vector<bitset<N>> dp(n + 1); for (int u = 1; u <= n; ++u) { for (auto v : adj[u]) { deg[v] += 1; } } queue<int> Q; for (int u = 1; u <= n; ++u) { dp[u][u] = 1; if (!deg[u]) Q.push(u); } while (!Q.empty()) { int u = Q.front(); Q.pop(); for (auto to : adj[u]) { deg[to] -= 1; dp[to] |= dp[u]; if (!deg[to]) Q.push(to); } }
for (auto& [a, b, id] : que[c]) { if (dp[dsu.find(a)][dsu.find(b)] == 1) ans[id] = 1; } }
for (int i = 0; i < q; ++i) { cout << ans[i]; } cout << '\n'; }
UPD:如果强制在线也是可以做的。
把按钮编号看做权值,预处理从 a 到 b 的最短路(这里的最短指的是路径上权值最大的边最小),枚举起点跑 n 次 BFS(类似堆优化 dijkstra)。
但全源最短路的复杂度是 Θ(mn)=Θ(n3) 的,需要优化。减少边数的想法和上面类似:这道题的环很多,而且环中的点都是相互连通的。对于一个大小为 k 的连通块,实际上只有 k−1 条边是有用的,所以看似最坏有 n 个环 n2 条边,有用的最多只有 n−1 条。为保证双向连通,连双向边,这样总边数是 2(n−1)+2l,复杂度可以通过。