제출 #1125100

#제출 시각아이디문제언어결과실행 시간메모리
1125100PanndaUsmjeri (COCI17_usmjeri)C++20
140 / 140
257 ms60124 KiB
#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;
        }
    }
    for (auto [u, v] : notes) {
        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 timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...