Solutions of Chongqing Megacity - MarisaOJ: Marisa Online Judge

Solutions of Chongqing Megacity

Select solution language

Write solution here.


User Avatar thaibeo123    Created at    5 likes

Ta thấy rằng để có được số đô thị có trọng số lớn hơn $0$, ta có thể lấy $n$ trừ đi số đô thị có trọng số là $0$, mà $0$ là trọng số bé nhất có thể. \ Do đó ta thấy rằng ta có thể dùng HLD để đếm số lượng đô thị có trọng số bé nhất: \ $\rightarrow$ Nếu trọng số bé nhất lớn hơn $0$, đáp án là $n$ \ $\rightarrow$ Nếu trọng số bé nhất bằng $0$, đáp án là $n$ trừ đi số đô thị có trọng số bé nhất \ \ Code mẫu: ``` #include <bits/stdc++.h> using namespace std; #define NAME "A" #define ll long long #define fi first #define se second #define pb push_back #define mp make_pair #define all(x) x.begin(), x.end() #define MASK(x) (1ll << (x)) #define BIT(x, i) (((x) >> (i)) & 1) #define countbit(x) (__builtin_popcountll(x)) const int N = 1e5 + 5; int n, q, timer; int p[N], sz[N], tin[N], h[N], hi[N]; vector<int> g[N]; pair<ll, int> operator + (pair<ll, int> a, pair<ll, int> b) { pair<ll, int> res; res.fi = min(a.fi, b.fi); if (res.fi == a.fi) res.se += a.se; if (res.fi == b.fi) res.se += b.se; return res; } struct SegmentTree { vector<pair<ll, int>> st; vector<ll> lazy; SegmentTree() {} SegmentTree(int n): st((n + 3) << 2), lazy((n + 3) << 2, 0) {} void build(int l = 1, int r = n, int x = 1) { if (l == r) { st[x] = {0, 1}; return; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); st[x] = st[x << 1] + st[x << 1 | 1]; } void down(int x) { st[x << 1].fi += lazy[x]; st[x << 1 | 1].fi += lazy[x]; lazy[x << 1] += lazy[x]; lazy[x << 1 | 1] += lazy[x]; lazy[x] = 0; } void update(int u, int v, int val, int l = 1, int r = n, int x = 1) { if (l > v || r < u) return; if (l >= u && r <= v) { st[x].fi += val; lazy[x] += val; return; } int mid = (l + r) >> 1; down(x); update(u, v, val, l, mid, x << 1); update(u, v, val, mid + 1, r, x << 1 | 1); st[x] = st[x << 1] + st[x << 1 | 1]; } pair<ll, int> get(int u, int v, int l = 1, int r = n, int x = 1) { if (l > v || r < u) return {1e18, 0}; if (l >= u && r <= v) return st[x]; int mid = (l + r) >> 1; down(x); if (v <= mid) return get(u, v, l, mid, x << 1); if (u > mid) return get(u, v, mid + 1, r, x << 1 | 1); return get(u, v, l, mid, x << 1) + get(u, v, mid + 1, r, x << 1 | 1); } }; SegmentTree st; void preprocess(int u, int par) { sz[u] = 1; p[u] = par; hi[u] = hi[par] + 1; for (int v : g[u]) { if (v == par) continue; preprocess(v, u); sz[u] += sz[v]; } } void hld(int u, int par, int head) { tin[u] = ++timer; h[u] = head; int beo = 0; for (int v : g[u]) { if (v != par && sz[v] > sz[beo]) { beo = v; } } if (beo) { hld(beo, u, head); } for (int v : g[u]) { if (v != par && v != beo) { hld(v, u, v); } } } void update(int u, int v, int val) { while (h[u] != h[v]) { if (hi[h[u]] < hi[h[v]]) { swap(u, v); } st.update(tin[h[u]], tin[u], val); u = p[h[u]]; } if (hi[u] > hi[v]) swap(u, v); st.update(tin[u], tin[v], val); } ll get(int u, int v) { ll res = 1e18; while (h[u] != h[v]) { if (hi[h[u]] < hi[h[v]]) { swap(u, v); } res = min(res, st.get(tin[h[u]], tin[u]).fi); u = p[h[u]]; } if (hi[u] > hi[v]) swap(u, v); res = min(res, st.get(tin[u], tin[v]).fi); return res; } void input() { cin >> n >> q; for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; g[u].pb(v); g[v].pb(u); } st = SegmentTree(n); } void solve() { preprocess(1, 0); hld(1, 0, 1); st.build(); while (q--) { int op, u, v; ll k; cin >> op >> u >> v >> k; if (op == 1) { update(u, v, k); } else { ll ad = get(u, v); ad = min(ad, k); update(u, v, -ad); } pair<ll, int> res = st.st[1]; int ans = n; if (res.fi == 0) { ans -= res.se; } cout << ans << "\n"; } } int main() { if (fopen(NAME".INP", "r")) { freopen(NAME".INP", "r", stdin); freopen(NAME".OUT", "w", stdout); } cin.tie(0)->sync_with_stdio(0); int t = 1; //cin >> t; while (t--) { input(); solve(); } return 0; } ```