CodeForces 1555F Good Graph
题目传送门:CodeForces 1555F Good Graph
Statement:
定义一张图为好图当且仅当图中所有简单环的\(xor\)为\(1\)。按顺序给定\(q\)条边,边权\(\in\{0,1\}\)。初始图上无边,按顺序依次考虑每条边,若这条边加入后图依旧是好图,那么可以加入,否则不能加入。输出每条边是否加入。
\(n,q\leq 3\cdot10^{5}\)
Solution:
可以发现图中一定不存在两个环有公共边。
那么一开始把改变联通性的边先加入,这样显然不影响答案。
加完后图变成了森林,再依次考虑构成环的边。
若\(u\)到\(v\)的路径上已经存在一个环了,那么这条边不能加入,否则加入并且把\(u\)到\(v\)路径上的边打上标记。
边上打标记显然可以转成向点打标记。
这样看上去要树剖,但是认真分析后可以发现每条边只会被加人一次,也就是每个点只会被加人一次,那么可以用DFS序的树状数组维护子树加,查询链和。
时间复杂度为\(\mathcal O(Q\log_2N)\)。
code:
#include <bits/stdc++.h>
template <typename T>
struct BIT {
int N;
std::vector <T> Tree;
BIT () {}
BIT (int n) : N(n) {
Tree = std::vector <int> (N + 1, 0);
}
inline void add(int p, int v) {
while (p <= N)
Tree[p] += v, p += p & -p;
}
inline int query(int p) {
p = std::min(p, N);
int res = 0;
while (p)
res += Tree[p], p -= p & -p;
return res;
}
};
int main(void) {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int n, q;
std::cin >> n >> q;
std::vector <std::tuple <int, int, int>> A;
std::vector <int> uf(n, -1);
std::function <int(int)> findPa = [&](int a) {
return uf[a] < 0 ? a : (uf[a] = findPa(uf[a]));
};
auto mergeTree = [&](int a, int b) {
a = findPa(a), b = findPa(b);
if (a ^ b) {
if (uf[a] > uf[b])
std::swap(a, b);
uf[a] += uf[b], uf[b] = a;
return true;
}
return false;
};
std::vector <std::vector <std::pair <int, int>>> adj(n);
std::vector <std::vector <int>> query(n);
std::vector <bool> isLink(q, 0);
for (int i = 0; i < q; ++i) {
int u, v, w;
std::cin >> u >> v >> w, --u, --v;
A.push_back(std::make_tuple(u, v, w));
if (mergeTree(u, v)) {
adj[u].push_back(std::make_pair(v, w)),
adj[v].push_back(std::make_pair(u, w));
isLink[i] = true;
} else {
query[u].push_back(i), query[v].push_back(i);
}
}
std::vector <int> Lca(q, 0), dfn(n, 0), fa(n, 0), sz(n, 0), dist(n, 0);
for (int i = 0; i < n; ++i)
uf[i] = -1;
int _clock = 0;
std::function <void(int, int)> getLca = [&](int u, int pa) {
dfn[u] = ++_clock;
sz[u] = 1;
for (auto nxt : adj[u]) {
int v = nxt.first;
int w = nxt.second;
if (v == pa)
continue;
dist[v] = dist[u] ^ w, getLca(v, u), sz[u] += sz[v];
uf[v] = fa[v] = u;
}
for (int i : query[u]) {
int p = std::get <0> (A[i]);
int q = std::get <1> (A[i]);
int o = p ^ q ^ u;
if (dfn[o])
Lca[i] = findPa(o);
}
};
for (int i = 0; i < n; ++i)
if (!dfn[i])
getLca(i, i);
BIT <int> R(n + 1);
for (int i = 0; i < q; ++i) {
if (isLink[i]) {
std::cout << "Yes\n";
continue;
}
int u = std::get <0> (A[i]);
int v = std::get <1> (A[i]);
int w = std::get <2> (A[i]);
int lca = Lca[i];
if ((dist[u] ^ dist[v] ^ w) && R.query(dfn[u]) == R.query(dfn[lca]) && R.query(dfn[v]) == R.query(dfn[lca])) {
std::cout << "Yes\n";
while (u ^ lca) {
R.add(dfn[u], 1);
R.add(dfn[u] + sz[u], -1);
u = fa[u];
}
while (v ^ lca) {
R.add(dfn[v], 1),
R.add(dfn[v] + sz[v], -1);
v = fa[v];
}
} else {
std::cout << "No\n";
}
}
return 0;
}

浙公网安备 33010602011771号