【思路要点】
- 离线操作,我们需要求出各城市破产的时间来回答询问。
- 考虑二分答案,我们需要能够回答形如 “ x x x 城市在 y y y 时刻遭受的损失” 的问题。
- 对于一个修改,我们可以将其拆分为在 O ( L o g V ) O(LogV) O(LogV) 个节点处向下传导至多 O ( L o g V ) O(LogV) O(LogV) 层的损失,在询问时我们只需查询其至多 O ( L o g V ) O(LogV) O(LogV) 个祖先对对应深度造成的损失即可。
- 修改的结果可以使用 v e c t o r vector vector 方便地可持久化,单次修改时间复杂度为 O ( L o g 2 V ) O(Log^2V) O(Log2V) ;询问单个节点对对应深度造成的损失需要在 v e c t o r vector vector 中二分,因此单次回答上文二分的询问,时间复杂度为 O ( L o g 2 V ) O(Log^2V) O(Log2V) ,得出一个城市破产的时间,时间复杂度为 O ( L o g Q L o g 2 V ) O(LogQLog^2V) O(LogQLog2V) 。
- 考虑用整体二分代替二分,在 v e c t o r vector vector 中二分的步骤可改为单调地移动指针,可以省去瓶颈处在 v e c t o r vector vector 中二分的复杂度。
- 修改时间复杂度 O ( Q L o g 2 V ) O(QLog^2V) O(QLog2V) , v e c t o r vector vector 中元素总数 O ( Q L o g V ) O(QLogV) O(QLogV) ;整体二分的询问总数 O ( N L o g Q ) O(NLogQ) O(NLogQ) ,单次询问访问祖先数量 O ( L o g V ) O(LogV) O(LogV) ;指针移动总数 O ( Q L o g Q L o g V ) O(QLogQLogV) O(QLogQLogV) 。
- 总时间复杂度 O ( N L o g 2 N ) O(NLog^2N) O(NLog2N) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int MAXLOG = 15; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct BinaryIndexTree { int n, a[MAXN]; void init(int x) { n = x; memset(a, 0, sizeof(a)); } void modify(int x, int d) { for (int i = x; i <= n; i += i & -i) a[i] += d; } int query(int l, int r) { int ans = 0; for (int i = r; i >= 1; i -= i & -i) ans += a[i]; for (int i = l - 1; i >= 1; i -= i & -i) ans -= a[i]; return ans; } } BIT; vector <int> a[MAXN]; int n, s, m, q, val[MAXN]; pair <int, int> qry[MAXN]; int timer, dfn[MAXN], rit[MAXN], father[MAXN], depth[MAXN]; int death[MAXN], pointer[MAXN]; vector <pair <int, vector <int>>> b[MAXN]; vector <int> unit() { vector <int> ans (MAXLOG); for (int i = 0; i < MAXLOG; i++) ans[i] = 0; return ans; } vector <int> makev(int val) { vector <int> ans (MAXLOG); for (int i = 0; i < MAXLOG; i++, val >>= 1) ans[i] = val; return ans; } vector <int> recess(vector <int> ans) { for (int i = 0; i < MAXLOG - 1; i++) ans[i] = ans[i + 1]; ans[MAXLOG - 1] = 0; return ans; } vector <int> operator + (vector <int> a, vector <int> b) { vector <int> ans (MAXLOG); for (int i = 0; i < MAXLOG; i++) ans[i] = a[i] + b[i]; return ans; } vector <int> operator - (vector <int> a, vector <int> b) { vector <int> ans (MAXLOG); for (int i = 0; i < MAXLOG; i++) ans[i] = a[i] - b[i]; return ans; } void modify(int x, int y) { static int pos[MAXLOG]; static vector <int> goal[MAXLOG]; int tot = 1; pos[0] = x, goal[0] = makev(y); while (tot < MAXLOG && pos[tot - 1] != 1) { pos[tot] = father[pos[tot - 1]]; goal[tot] = recess(goal[tot - 1]); tot++; } vector <int> ex = unit(); for (int i = tot - 1; i >= 0; i--) { vector <int> tmp = goal[i] - ex; b[pos[i]].emplace_back(m, b[pos[i]].back().second + tmp); ex = recess(ex + tmp); } } void dfs(int pos, int fa) { father[pos] = fa; depth[pos] = depth[fa] + 1; dfn[pos] = ++timer; for (auto x : a[pos]) if (x != fa) dfs(x, pos); rit[pos] = timer; } void init() { read(n); for (int i = 1; i <= n; i++) read(val[i]); for (int i = 1; i <= n - 1; i++) { int x, y; read(x), read(y); a[x].push_back(y); a[y].push_back(x); } dfs(1, 0); for (int i = 1; i <= n; i++) { b[i].resize(1); b[i][0].first = 0; b[i][0].second = unit(); } read(s); for (int i = 1; i <= s; i++) { int opt, x; read(opt), read(x); if (opt == 1) { int y; read(y); m++; modify(x, y); } else qry[++q] = make_pair(m, x); } } void debug() { for (int i = 1; i <= n; i++) { cerr << i << endl; for (auto x : b[i]) { cerr << x.first; for (auto y : x.second) cerr << ' ' << y; cerr << endl; } cerr << endl; } } int query(int pos, int timer) { int ans = 0; for (int i = 0; i < MAXLOG && pos != 0; i++, pos = father[pos]) { while (pointer[pos] < b[pos].size() - 1 && b[pos][pointer[pos] + 1].first <= timer) pointer[pos]++; ans += b[pos][pointer[pos]].second[i]; } return ans; } bool cmp(pair <int, pair <int, int>> x, pair <int, pair <int, int>> y) { return x.second.first < y.second.first; } void gdeath() { static deque <pair <int, pair <int, int>>> deq; for (int i = 1; i <= n; i++) deq.emplace_back(i, make_pair(1, m + 1)); int home = m + 1; while (!deq.empty()) { int pos = deq.front().first; pair <int, int> rng = deq.front().second; if (rng.first == rng.second) { death[pos] = rng.first; deq.pop_front(); continue; } int mid = (rng.first + rng.second) / 2; if (mid < home) { home = 0; for (int i = 1; i <= n; i++) pointer[i] = 0; sort(deq.begin(), deq.end(), cmp); continue; } int tmp = query(pos, mid); home = mid; if (tmp >= val[pos]) deq.emplace_back(pos, make_pair(rng.first, mid)); else deq.emplace_back(pos, make_pair(mid + 1, rng.second)); deq.pop_front(); } } void answer() { BIT.init(n); static vector <int> home[MAXN]; for (int i = 1; i <= n; i++) home[death[i]].push_back(i); for (int i = 1, timer = 0; i <= q; i++) { while (timer < qry[i].first) { timer++; for (auto x : home[timer]) BIT.modify(dfn[x], 1); } writeln(BIT.query(dfn[qry[i].second], rit[qry[i].second])); } } int main() { freopen("pang.in", "r", stdin); freopen("pang.out", "w", stdout); init(); //debug(); gdeath(); answer(); return 0; }