QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#223310#7608. Cliquesucup-team1631#WA 1ms3584kbC++2315.5kb2023-10-21 23:54:072023-10-21 23:54:08

Judging History

你现在查看的是最新测评结果

  • [2023-10-21 23:54:08]
  • 评测
  • 测评结果:WA
  • 用时:1ms
  • 内存:3584kb
  • [2023-10-21 23:54:07]
  • 提交

answer

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t)-1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T>
bool chmax(T& a, const T& b) {
    return a < b ? (a = b, 1) : 0;
}
template <typename T>
bool chmin(T& a, const T& b) {
    return a > b ? (a = b, 1) : 0;
}

template <int mod>
class Modint {
    using mint = Modint;
    static_assert(mod > 0, "Modulus must be positive");

   public:
    static constexpr int get_mod() noexcept { return mod; }

    constexpr Modint(long long y = 0) noexcept
        : x(y >= 0 ? y % mod : (y % mod + mod) % mod) {}

    constexpr int value() const noexcept { return x; }

    constexpr mint& operator+=(const mint& r) noexcept {
        if ((x += r.x) >= mod) x -= mod;
        return *this;
    }
    constexpr mint& operator-=(const mint& r) noexcept {
        if ((x += mod - r.x) >= mod) x -= mod;
        return *this;
    }
    constexpr mint& operator*=(const mint& r) noexcept {
        x = static_cast<int>(1LL * x * r.x % mod);
        return *this;
    }
    constexpr mint& operator/=(const mint& r) noexcept {
        *this *= r.inv();
        return *this;
    }

    constexpr mint operator-() const noexcept { return mint(-x); }

    constexpr mint operator+(const mint& r) const noexcept {
        return mint(*this) += r;
    }
    constexpr mint operator-(const mint& r) const noexcept {
        return mint(*this) -= r;
    }
    constexpr mint operator*(const mint& r) const noexcept {
        return mint(*this) *= r;
    }
    constexpr mint operator/(const mint& r) const noexcept {
        return mint(*this) /= r;
    }

    constexpr bool operator==(const mint& r) const noexcept { return x == r.x; }
    constexpr bool operator!=(const mint& r) const noexcept { return x != r.x; }

    constexpr mint inv() const noexcept {
        int a = x, b = mod, u = 1, v = 0;
        while (b > 0) {
            int t = a / b;
            std::swap(a -= t * b, b);
            std::swap(u -= t * v, v);
        }
        return mint(u);
    }

    constexpr mint pow(long long n) const noexcept {
        mint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend std::ostream& operator<<(std::ostream& os, const mint& r) {
        return os << r.x;
    }

    friend std::istream& operator>>(std::istream& is, mint& r) {
        long long t;
        is >> t;
        r = mint(t);
        return is;
    }

   private:
    int x;
};

using mint = Modint<(int)1e9 + 7>;

class LCA {
   public:
    LCA() = default;
    LCA(const std::vector<std::vector<int>>& G, int root)
        : G(G), LOG(32 - __builtin_clz(G.size())), depth(G.size()) {
        int V = G.size();
        table.assign(LOG, std::vector<int>(V, -1));

        dfs(root, -1, 0);

        for (int k = 0; k < LOG - 1; ++k) {
            for (int v = 0; v < V; ++v) {
                if (table[k][v] >= 0) {
                    table[k + 1][v] = table[k][table[k][v]];
                }
            }
        }
    }

    int query(int u, int v) const {
        if (depth[u] > depth[v]) std::swap(u, v);

        // go up to the same depth
        for (int k = 0; k < LOG; ++k) {
            if ((depth[v] - depth[u]) >> k & 1) {
                v = table[k][v];
            }
        }
        if (u == v) return u;

        for (int k = LOG - 1; k >= 0; --k) {
            if (table[k][u] != table[k][v]) {
                u = table[k][u];
                v = table[k][v];
            }
        }
        return table[0][u];
    }

    int dist(int u, int v) const {
        return depth[u] + depth[v] - 2 * depth[query(u, v)];
    }

    int parent(int v, int k) const {
        for (int i = LOG - 1; i >= 0; --i) {
            if (k >= (1 << i)) {
                v = table[i][v];
                k -= 1 << i;
            }
        }
        return v;
    }

    int jump(int u, int v, int k) const {
        int l = query(u, v);
        int du = depth[u] - depth[l];
        int dv = depth[v] - depth[l];
        if (du + dv < k) return -1;
        if (k < du) return parent(u, k);
        return parent(v, du + dv - k);
    }

   protected:
    const std::vector<std::vector<int>>& G;
    const int LOG;
    std::vector<std::vector<int>> table;
    std::vector<int> depth;

    void dfs(int v, int p, int d) {
        table[0][v] = p;
        depth[v] = d;
        for (int c : G[v]) {
            if (c != p) dfs(c, v, d + 1);
        }
    }
};

template <typename M>
class HLD {
    using T = typename M::T;

   public:
    HLD() = default;
    HLD(const std::vector<std::vector<int>>& G, bool edge)
        : G(G),
          size(G.size()),
          depth(G.size()),
          par(G.size(), -1),
          in(G.size()),
          out(G.size()),
          head(G.size()),
          heavy(G.size(), -1),
          edge(edge) {
        dfs(0);
        decompose(0, 0);
    }

    template <typename F>
    void update(int v, const T& x, const F& f) const {
        f(in[v], x);
    }

    template <typename F>
    void update_edge(int u, int v, const T& x, const F& f) const {
        if (in[u] > in[v]) std::swap(u, v);
        f(in[v], x);
    }

    template <typename E, typename F>
    void update(int u, int v, const E& x, const F& f) const {
        while (head[u] != head[v]) {
            if (in[head[u]] > in[head[v]]) std::swap(u, v);
            f(in[head[v]], in[v] + 1, x);
            v = par[head[v]];
        }
        if (in[u] > in[v]) std::swap(u, v);
        f(in[u] + edge, in[v] + 1, x);
    }

    template <typename F, typename Flip>
    T path_fold(int u, int v, const F& f, const Flip& flip) const {
        bool flipped = false;
        T resu = M::id(), resv = M::id();
        while (head[u] != head[v]) {
            if (in[head[u]] > in[head[v]]) {
                std::swap(u, v);
                std::swap(resu, resv);
                flipped ^= true;
            }
            T val = f(in[head[v]], in[v] + 1);
            resv = M::op(val, resv);
            v = par[head[v]];
        }
        if (in[u] > in[v]) {
            std::swap(u, v);
            std::swap(resu, resv);
            flipped ^= true;
        }
        T val = f(in[u] + edge, in[v] + 1);
        resv = M::op(val, resv);
        resv = M::op(flip(resu), resv);
        if (flipped) {
            resv = flip(resv);
        }
        return resv;
    }

    template <typename F>
    T path_fold(int u, int v, const F& f) const {
        return path_fold(u, v, f, [&](auto& v) { return v; });
    }

    template <typename F>
    T subtree_fold(int v, const F& f) const {
        return f(in[v] + edge, out[v]);
    }

    int lca(int u, int v) const {
        while (true) {
            if (in[u] > in[v]) std::swap(u, v);
            if (head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }

    int dist(int u, int v) const {
        return depth[u] + depth[v] - 2 * depth[lca(u, v)];
    }

   private:
    std::vector<std::vector<int>> G;
    std::vector<int> size, depth, par, in, out, head, heavy;
    bool edge;
    int cur_pos = 0;

    void dfs(int v) {
        size[v] = 1;
        int max_size = 0;
        for (int c : G[v]) {
            if (c == par[v]) continue;
            par[c] = v;
            depth[c] = depth[v] + 1;
            dfs(c);
            size[v] += size[c];
            if (size[c] > max_size) {
                max_size = size[c];
                heavy[v] = c;
            }
        }
    }

    void decompose(int v, int h) {
        head[v] = h;
        in[v] = cur_pos++;
        if (heavy[v] != -1) decompose(heavy[v], h);
        for (int c : G[v]) {
            if (c != par[v] && c != heavy[v]) decompose(c, c);
        }
        out[v] = cur_pos;
    }
};

template <typename M, typename O,
          typename M::T (*act)(typename M::T, typename O::T)>
class LazySegmentTree {
    using T = typename M::T;
    using E = typename O::T;

   public:
    LazySegmentTree() = default;
    explicit LazySegmentTree(int n)
        : LazySegmentTree(std::vector<T>(n, M::id())) {}
    explicit LazySegmentTree(const std::vector<T>& v) {
        size = 1;
        while (size < (int)v.size()) size <<= 1;
        node.resize(2 * size, M::id());
        lazy.resize(2 * size, O::id());
        std::copy(v.begin(), v.end(), node.begin() + size);
        for (int i = size - 1; i > 0; --i)
            node[i] = M::op(node[2 * i], node[2 * i + 1]);
    }

    T operator[](int k) { return fold(k, k + 1); }

    void update(int l, int r, const E& x) { update(l, r, x, 1, 0, size); }

    T fold(int l, int r) { return fold(l, r, 1, 0, size); }

    template <typename F>
    int find_first(int l, F cond) {
        T v = M::id();
        return find_first(l, size, 1, 0, size, v, cond);
    }

    template <typename F>
    int find_last(int r, F cond) {
        T v = M::id();
        return find_last(0, r, 1, 0, size, v, cond);
    }

   private:
    int size;
    std::vector<T> node;
    std::vector<E> lazy;

    void push(int k) {
        if (lazy[k] == O::id()) return;
        if (k < size) {
            lazy[2 * k] = O::op(lazy[2 * k], lazy[k]);
            lazy[2 * k + 1] = O::op(lazy[2 * k + 1], lazy[k]);
        }
        node[k] = act(node[k], lazy[k]);
        lazy[k] = O::id();
    }

    void update(int a, int b, const E& x, int k, int l, int r) {
        push(k);
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = O::op(lazy[k], x);
            push(k);
            return;
        }
        int m = (l + r) / 2;
        update(a, b, x, 2 * k, l, m);
        update(a, b, x, 2 * k + 1, m, r);
        node[k] = M::op(node[2 * k], node[2 * k + 1]);
    }

    T fold(int a, int b, int k, int l, int r) {
        push(k);
        if (r <= a || b <= l) return M::id();
        if (a <= l && r <= b) return node[k];
        int m = (l + r) / 2;
        return M::op(fold(a, b, 2 * k, l, m), fold(a, b, 2 * k + 1, m, r));
    }

    template <typename F>
    int find_first(int a, int b, int k, int l, int r, T& v, F cond) {
        push(k);
        if (r <= a) return -1;
        if (b <= l) return l;
        if (a <= l && r <= b && !cond(M::op(v, node[k]))) {
            v = M::op(v, node[k]);
            return -1;
        }
        if (r - l == 1) return r;
        int m = (l + r) / 2;
        int res = find_first(a, b, 2 * k, l, m, v, cond);
        if (res != -1) return res;
        return find_first(a, b, 2 * k + 1, m, r, v, cond);
    }

    template <typename F>
    int find_last(int a, int b, int k, int l, int r, T& v, F cond) {
        push(k);
        if (b <= l) return -1;
        if (r <= a) return r;
        if (a <= l && r <= b && !cond(M::op(node[k], v))) {
            v = M::op(node[k], v);
            return -1;
        }
        if (r - l == 1) return l;
        int m = (l + r) / 2;
        int res = find_last(a, b, 2 * k + 1, m, r, v, cond);
        if (res != -1) return res;
        return find_last(a, b, 2 * k, l, m, v, cond);
    }
};

struct AddRangeMonoid {
    using T = pair<mint, mint>;
    static T id() { return {0, 0}; }
    static T op(T a, T b) { return {a.first + b.first, a.second + b.second}; }
};

struct AddRangeMonoidInt {
    using T = pair<int, int>;
    static T id() { return {0, 0}; }
    static T op(T a, T b) { return {a.first + b.first, a.second + b.second}; }
};

struct AddMonoid {
    using T = int;
    static T id() { return 0; }
    static T op(T a, T b) { return a + b; }
};

struct MulUpdateMonoid {
    using T = pair<bool, mint>;  // (set if true else mul, x)
    static T id() { return {false, 1}; }
    static T op(T a, T b) {
        if (b.first) {
            return b;
        } else {
            return {a.first, a.second * b.second};
        }
    }
};

AddRangeMonoid::T act(AddRangeMonoid::T a, MulUpdateMonoid::T b) {
    if (b.first) {
        return {b.second * a.second, a.second};
    } else {
        return {b.second * a.first, a.second};
    }
}

AddRangeMonoidInt::T act2(AddRangeMonoidInt::T a, AddMonoid::T b) {
    return {a.first + a.second * b, a.second};
}

template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); ++i) {
        os << v[i];
        if (i < (int)v.size() - 1) os << " ";
    }
    return os;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n;
    cin >> n;
    vector<vector<int>> T(n);
    rep(i, 0, n - 1) {
        int a, b;
        cin >> a >> b;
        --a, --b;
        T[a].push_back(b);
        T[b].push_back(a);
    }
    int q;
    cin >> q;

    LCA lca(T, 0);

    vector<int> cnt(n);

    HLD<AddRangeMonoid> hld_val(T, false);
    vector<pair<mint, mint>> val(n, {0, 1});
    LazySegmentTree<AddRangeMonoid, MulUpdateMonoid, act> st_val(val);

    auto update_val = [&](int l, int r, auto& x) { st_val.update(l, r, x); };

    auto fold_val = [&](int l, int r) { return st_val.fold(l, r); };

    HLD<AddRangeMonoidInt> hld_cover(T, false);
    vector<pair<int, int>> cover(n, {0, 1});
    LazySegmentTree<AddRangeMonoidInt, AddMonoid, act2> st_cover(cover);

    auto update_cover = [&](int l, int r, auto& x) {
        st_cover.update(l, r, x);
    };

    auto fold_cover = [&](int l, int r) { return st_cover.fold(l, r); };

    vector<mint> pow2(n + q + 1, 1);
    rep(i, 1, n + q + 1) pow2[i] = pow2[i - 1] * 2;
    mint inv2 = mint(1) / 2;

    auto add = [&](int u, int v) {
        ++cnt[u];
        int c = hld_cover.path_fold(u, u, fold_cover).first;
        hld_val.update(u, u, make_pair(true, (pow2[cnt[u]] - 1) * pow2[c]),
                       update_val);
        if (u != v) {
            int u2 = lca.jump(u, v, 1);
            hld_cover.update(u2, v, 1, update_cover);
            hld_val.update(u2, v, make_pair(false, 2), update_val);
        }
    };

    auto remove = [&](int u, int v) {
        --cnt[u];
        int c = hld_cover.path_fold(u, u, fold_cover).first;
        hld_val.update(u, u, make_pair(true, (pow2[cnt[u]] - 1) * pow2[c]),
                       update_val);
        if (u != v) {
            int u2 = lca.jump(u, v, 1);
            hld_cover.update(u2, v, -1, update_cover);
            hld_val.update(u2, v, make_pair(false, inv2), update_val);
        }
    };

    int excess = 0;

    while (q--) {
        char c;
        int v, w;
        cin >> c >> v >> w;
        --v, --w;
        if (c == '+') {
            int l = lca.query(v, w);
            if (l == v) {
                add(v, w);
            } else if (l == w) {
                add(w, v);
            } else {
                add(l, v);
                add(lca.jump(l, w, 1), w);
                ++excess;
            }
        } else {
            int l = lca.query(v, w);
            if (l == v) {
                remove(v, w);
            } else if (l == w) {
                remove(w, v);
            } else {
                remove(l, v);
                remove(lca.jump(l, w, 1), w);
                --excess;
            }
        }
        cout << fold_val(0, n).first  - excess << endl;
    }
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3584kb

input:

5
1 2
5 1
2 3
4 2
6
+ 4 5
+ 2 2
+ 1 3
- 2 2
+ 2 3
+ 4 4

output:

1
3
7
3
7
9

result:

ok 6 lines

Test #2:

score: -100
Wrong Answer
time: 1ms
memory: 3520kb

input:

20
8 7
19 10
12 14
3 16
17 13
7 10
5 6
1 9
15 12
5 2
16 13
3 11
20 14
18 6
1 14
16 20
11 10
3 4
20 6
30
+ 10 20
+ 14 20
+ 12 17
- 14 20
- 12 17
+ 4 6
+ 8 20
+ 3 6
- 10 20
+ 2 17
+ 1 16
+ 6 10
+ 9 10
+ 5 15
+ 7 8
- 7 8
+ 2 5
+ 3 18
+ 1 20
+ 8 16
- 3 18
- 5 15
+ 4 20
+ 14 16
- 4 6
+ 8 19
+ 4 7
- 1 16
...

output:

1
3
8
3
1
3
7
16
8
26
50
119
232
372
374
372
376
759
1273
1529
762
492
972
1932
965
981
1076
594
854
411

result:

wrong answer 3rd lines differ - expected: '7', found: '8'