QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#112283 | #6559. A Tree and Two Edges | ITMO_pengzoo# | RE | 2ms | 3492kb | C++20 | 6.4kb | 2023-06-11 01:53:01 | 2023-06-11 01:53:06 |
Judging History
answer
// Nikita Golikov, 2023
#include <bits/stdc++.h>
using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
#ifdef GOLIKOV
#include "/Users/golikovnik/contests/debug.h"
#else
#define debug(...) ;
#endif
template <class A, class B>
bool smin(A& x, B&& y) {
if (y < x) {
x = y;
return true;
}
return false;
}
template <class A, class B>
bool smax(A& x, B&& y) {
if (x < y) {
x = y;
return true;
}
return false;
}
struct LCA {
vector<vector<int>> graph;
int root;
int n;
vector<int> parent, jump, depth, tin, tout;
int timer;
LCA(vector<vector<int>> g, int root_ = 0) : graph(move(g)), root(root_) {
n = int(graph.size());
build();
}
template <class F>
int up(int v, F const& f) {
while (v != root) {
int jv = jump[v];
if (f(jv)) {
v = jv;
} else {
int pv = parent[v];
if (f(pv)) {
v = pv;
} else {
return v;
}
}
}
return root;
}
int up(int v, int d) {
int nd = depth[v] - d;
assert(nd >= 0);
return up(v, [&](int u) {
return depth[u] >= nd;
});
}
bool anc(int v, int u) {
return tin[v] <= tin[u] && tout[u] <= tout[v];
}
int lca(int u, int v) {
return anc(u, v) ? u : parent[up(u, [&](int x) { return !anc(x, v); })];
}
int operator()(int u, int v) {
return lca(u, v);
}
int dist(int u, int v) {
return depth[u] + depth[v] - 2 * depth[lca(u, v)];
}
// kth vertex on path u->v
int kth(int u, int v, int k) {
int w = lca(u, v);
assert(k <= depth[u] + depth[v] - 2 * depth[w]);
if (k <= depth[u] - depth[w]) {
return up(u, k);
}
k -= depth[u] - depth[w];
return up(v, depth[v] - depth[w] - k);
}
void dfs(int v) {
tin[v] = timer++;
for (int u : graph[v]) {
if (u == parent[v]) {
continue;
}
depth[u] = depth[v] + 1;
parent[u] = v;
int dpar = depth[v];
int dparj = depth[jump[v]];
int dparjj = depth[jump[jump[v]]];
jump[u] = (dparj - dpar == dparjj - dparj ? jump[jump[v]] : v);
dfs(u);
}
tout[v] = timer;
}
void build() {
parent.resize(n, -1);
jump.resize(n, -1);
depth.resize(n, -1);
tin.resize(n, -1);
tout.resize(n, -1);
timer = 0;
depth[root] = 0;
parent[root] = jump[root] = root;
dfs(root);
}
};
int main() {
#ifdef GOLIKOV
assert(freopen("in", "rt", stdin));
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, q;
cin >> n >> q;
vector<vector<int>> graph(n);
for (int i = 0; i < n + 1; ++i) {
int u, v;
cin >> u >> v;
--u, --v;
graph[u].push_back(v);
graph[v].push_back(u);
}
vector<bool> used(n);
vector<pair<int, int>> back;
vector<int> par(n);
vector<int> dep(n);
vector sum(4, vector<int>(n));
auto dfs = [&](auto self, int v, int p = -1) -> void {
used[v] = true;
for (int u : graph[v]) {
if (u == p) {
continue;
}
if (used[u]) {
if (dep[u] > dep[v]) {
back.emplace_back(u, v);
}
} else {
dep[u] = dep[v] + 1;
par[u] = v;
self(self, u, v);
}
}
};
dfs(dfs, 0);
assert(int(back.size()) == 2);
vector<int> fe(n);
for (int i = 0; i < 2; ++i) {
auto[u, v] = back[i];
while (u != v) {
fe[u] |= 1 << i;
u = par[u];
}
}
fill(used.begin(), used.end(), false);
vector<vector<int>> tree(n);
vector<int> total(4);
auto dfs2 = [&](auto self, int v, int p = -1) -> void {
used[v] = true;
for (int u : graph[v]) {
if (u == p) {
continue;
}
total[fe[u]] += 1;
if (!used[u]) {
tree[v].push_back(u);
tree[u].push_back(v);
for (int t = 0; t < 4; ++t) {
sum[t][u] += sum[t][v];
}
sum[fe[u]][u] += 1;
self(self, u, v);
}
}
};
dfs2(dfs2, 0);
auto lca = LCA(tree);
auto GetCnt = [&](int t, int u, int v) {
return sum[t][u] + sum[t][v] - 2 * sum[t][lca(u, v)];
};
vector<int> tp(n);
vector<bool> onCycle(n);
for (int t = 1; t < 4; ++t) {
vector<vector<int>> g(n);
vector<int> d(n);
for (int i = 1; i < n; ++i) {
if (fe[i] == t) {
g[i].push_back(par[i]);
g[par[i]].push_back(i);
d[i]++;
d[par[i]]++;
}
}
if (t <= 2) {
auto[u, v] = back[t - 1];
d[u]++;
d[v]++;
g[u].push_back(v);
g[v].push_back(u);
}
int leaf = 0;
while (leaf < n && d[leaf] != 1) {
leaf++;
}
assert(leaf < n && d[leaf] == 1);
vector<int> path{leaf};
while (true) {
int cur = path.back();
int f = -1;
for (int v : g[cur]) {
if (cur == leaf || v != path.end()[-2]) {
f = v;
}
}
if (f < 0) {
break;
}
path.push_back(f);
}
assert(int(path.size()) >= 2);
for (int v : path) {
onCycle[v] = true;
}
for (int i = 1; i < int(path.size()) - 1; ++i) {
tp[path[i]] = t;
}
}
vector<int> closest(n, -1);
queue<int> qu;
for (int v = 0; v < n; ++v) {
if (onCycle[v]) {
closest[v] = v;
qu.push(v);
}
}
while (!qu.empty()) {
int v = qu.front(); qu.pop();
for (int u : graph[v]) {
if (closest[u] < 0) {
closest[u] = closest[v];
qu.push(u);
}
}
}
while (q--) {
int u, v;
cin >> u >> v;
--u, --v;
int c[4]{};
for (int t = 0; t < 4; ++t) {
c[t] = GetCnt(t, u, v);
}
if (!total[3]) {
// non intersecting
int ans = 1;
if (c[1]) {
ans *= 2;
}
if (c[2]) {
ans *= 2;
}
cout << ans << '\n';
continue;
}
u = closest[u];
v = closest[v];
if (u == v) {
cout << 1 << '\n';
} else if (tp[u] && tp[v] && tp[u] != tp[v]) {
cout << 4 << '\n';
} else {
cout << 3 << '\n';
}
}
#ifdef GOLIKOV
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 2ms
memory: 3492kb
input:
4 6 1 2 1 3 1 4 2 3 2 4 1 2 1 3 1 4 2 3 2 4 3 4
output:
3 3 3 3 3 4
result:
ok 6 lines
Test #2:
score: -100
Dangerous Syscalls
input:
6 4 1 2 1 3 1 6 2 3 3 4 3 5 4 5 1 2 1 3 1 4 1 6