#include <bits/stdc++.h>
using namespace std;
struct Tree {
vector<int> depth, parent, siz, head, begin, end, inv_begin;
Tree(const int &n, const vector<vector<int>> &adj, int root = 0) : depth(n), parent(n), siz(n), head(n), begin(n), end(n), inv_begin(n) {
auto dfs = [&](auto self, int u, int p) -> void {
depth[u] = p == -1 ? 0 : depth[p] + 1;
parent[u] = p;
siz[u] = 1;
for (int v : adj[u]) {
if (v == p) continue;
self(self, v, u);
siz[u] += siz[v];
}
};
dfs(dfs, root, -1);
int tim = 0;
auto decompose = [&](auto self, int u, int h) -> void {
head[u] = h;
int heavy = -1;
begin[u] = tim++;
inv_begin[begin[u]] = u;
for (int v : adj[u]) {
if (v == parent[u]) continue;
if (heavy == -1 || siz[v] > siz[heavy]) heavy = v;
}
if (heavy != -1) self(self, heavy, h);
for (int v : adj[u]) {
if (v == parent[u] || v == heavy) continue;
self(self, v, v);
}
end[u] = tim;
};
decompose(decompose, root, root);
}
int getDepth(int u) {
return depth[u];
}
int getParent(int u) {
return parent[u];
}
int getAncestor(int u, int k) { // returns the kth ancestor of u, -1 if out of tree. For example: 0th is u, 1st is parent(u),...
while (k > 0 && u != -1) {
if (k > depth[u] - depth[head[u]]) {
k -= depth[u] - depth[head[u]] + 1;
u = parent[head[u]];
} else {
u = inv_begin[begin[u] - k];
k = 0;
}
}
return u;
}
bool isDescendant(int upper, int lower) {
return begin[upper] <= begin[lower] && begin[lower] < end[upper];
}
bool isProperDescendant(int upper, int lower) {
return begin[upper] < begin[lower] && begin[lower] < end[upper];
}
int getLCA(int u, int v) {
for (; head[u] != head[v]; v = parent[head[v]]) {
if (depth[head[u]] > depth[head[v]]) swap(u, v);
}
if (depth[u] > depth[v]) swap(u, v);
return u;
}
int getDist(int u, int v) {
return depth[u] + depth[v] - 2 * depth[getLCA(u, v)];
}
int getIntermediate(int heavy, int u) { // returns the first node that isn't 'heavy' on the path from 'heavy' to 'u'
assert(heavy != u);
if (heavy != getLCA(u, heavy)) {
return parent[heavy];
}
while (head[u] != head[heavy]) {
u = head[u];
if (parent[u] == heavy) return u;
u = parent[u];
}
return inv_begin[begin[heavy] + 1];
}
int getNode(int u) { // maps nodes -> positions in the Euler tour
return begin[u];
}
int getInvNode(int p) { // maps Euler tour positions -> nodes
return inv_begin[p];
}
array<int, 2> getSubtree(int u) { // returns the subtree rooted at u, presented by the range of positions in the Euler tour
return array<int, 2>{ begin[u], end[u] };
}
vector<array<int, 2>> getPath(int u, int v) { // returns the path [u, v], presented by a list of O(log) ranges that are the positions in the Euler tour
vector<array<int, 2>> res;
for (; head[u] != head[v]; v = parent[head[v]]) {
if (depth[head[u]] > depth[head[v]]) swap(u, v);
res.push_back({ begin[head[v]], begin[v] + 1 });
}
if (depth[u] > depth[v]) swap(u, v);
res.push_back({ begin[u], begin[v] + 1 });
return res;
}
pair<vector<int>, vector<array<int, 2>>> virtualTree(vector<int> nodes) { // returns a pair: the list of nodes in the virtual tree (at most 2*|nodes|), and the list of edges of that virtual tree
sort(nodes.begin(), nodes.end(), [&](int u, int v) { return begin[u] < begin[v]; });
int siz = nodes.size();
for (int i = 0; i + 1 < siz; i++) {
nodes.push_back(getLCA(nodes[i], nodes[i + 1]));
}
sort(nodes.begin(), nodes.end(), [&](int u, int v) { return begin[u] < begin[v]; });
nodes.resize(unique(nodes.begin(), nodes.end()) - nodes.begin());
vector<array<int, 2>> edges;
vector<int> stk;
for (int u : nodes) {
while (!stk.empty() && !isProperDescendant(stk.back(), u)) {
stk.pop_back();
}
if (!stk.empty()) {
edges.push_back({stk.back(), u});
}
stk.push_back(u);
}
return {nodes, edges};
}
};
struct DSU {
int n;
vector<int> f;
DSU(int n) : n(n), f(n) { iota(f.begin(), f.end(), 0); }
int leader(int u) {
while (u != f[u]) {
u = f[u] = f[f[u]];
}
return u;
}
bool unionize(int u, int v) {
u = leader(u);
v = leader(v);
if (u == v) return false;
f[u] = v;
n--;
return true;
}
bool same(int u, int v) {
return leader(u) == leader(v);
}
int count() {
return n;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
u--;
v--;
adj[u].push_back(v);
adj[v].push_back(u);
}
Tree tree(n, adj);
DSU dsu(n);
vector<int> f(n, 1);
vector<array<int, 2>> notes;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
u--;
v--;
int uv = tree.getLCA(u, v);
f[u] = max(f[u], tree.getDepth(u) - tree.getDepth(uv));
f[v] = max(f[v], tree.getDepth(v) - tree.getDepth(uv));
if (uv != u && uv != v) {
notes.push_back({tree.getIntermediate(uv, u), tree.getIntermediate(uv, v)});
}
}
auto dfs = [&](auto self, int u, int p) -> void {
for (int v : adj[u]) {
if (v == p) continue;
self(self, v, u);
if (u == 0) continue;
if (f[v] > 1) dsu.unionize(v, u);
f[u] = max(f[u], f[v] - 1);
}
};
dfs(dfs, 0, -1);
for (auto [u, v] : notes) {
if (dsu.same(u, v)) {
cout << 0 << '\n';
return 0;
}
dsu.unionize(u, v);
}
int ans = 1;
for (int i = dsu.count() - 1; i > 0; i--) {
ans = 2 * ans % ((int)1e9 + 7);
}
cout << ans << '\n';
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |