题意
三种操作
- 在树上加点
- 给x号点及其子树所有点加权y
- 询问某点权值
思路
因为是动态加点的树难处理,考虑离线。
离线建树。
对子树进行操作,考虑dfs序。
暴力处理为
考虑树状数组进行差分,复杂度降为。
因为点再加上去之前点权为0,所以记录下加点时的点权,询问时再减去即可。
AC代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int maxn = 1e5 + 5; const ll inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; #define all(x) x.begin(), x.end() #define rall(x) x.rbegin(), x.rend() class qnode { public: int op, x, y; }; void dfs(int now, int& id, vector<vector<int>>& edge, vector<int>& l, vector<int>& r) { r[now] = l[now] = ++id; for (auto& it : edge[now]) { dfs(it, id, edge, l, r); r[now] = r[it]; } } class BIT { public: vector<ll> tree; int n; BIT(int _n) : n(_n), tree(_n + 1, 0) {} static int lowbit(int x) { return x & (-x); } ll query(int x) { ll ans = 0; while (x) { ans += tree[x]; x -= lowbit(x); } return ans; } void add(int x, ll val) { while (x <= n) { tree[x] += val; x += lowbit(x); } } }; int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int q; cin >> q; vector<qnode> a(q); int cnt = 1; for (int i = 0; i < q; ++i) { cin >> a[i].op >> a[i].x; if (a[i].op == 2) cin >> a[i].y; cnt += a[i].op == 1; } vector<vector<int>> edge(cnt, vector<int>()); for (int i = 0, nowid = 1; i < q; ++i) { if (a[i].op == 1) { edge[a[i].x].emplace_back(nowid); a[i].y = nowid++; } } vector<int> l(cnt), r(cnt); int id = 0; dfs(0, id, edge, l, r); vector<int> del(cnt); BIT T(cnt + 1); for (int i = 0; i < q; ++i) { if (a[i].op == 1) { int id = l[a[i].y]; del[id] = T.query(id); } if (a[i].op == 2) { T.add(l[a[i].x], a[i].y); T.add(r[a[i].x] + 1, -a[i].y); } if (a[i].op == 3) { int id = l[a[i].x]; cout << T.query(id) - del[id] << endl; } } return 0; }