QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#223310 | #7608. Cliques | ucup-team1631# | WA | 1ms | 3584kb | C++23 | 15.5kb | 2023-10-21 23:54:07 | 2023-10-21 23:54:08 |
Judging History
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'