Codeforces Round 907 (Div. 2) F. A Growing Tree(2000,子树修改)
Problem - 1891F - Codeforces
动态维护比较困难,可以发现一个节点的权值只跟他后面的2操作有关,我们可以先把树建好,记录所有操作,倒着枚举操作,如果当前操作是2,则修改x整个子树的值;如果当前操作是1,则记录下当前节点的权值为答案。
对于一个已经建好的树,如何修改整个子树的值?我们可以记录下这个树的dfs序,在这个过程中,回溯的时候可以记录下当前节点子树所对应dfs序的截止位置。我们直接对这个区间进行修改就可以了。可以使用差分树状数组
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
#define pii pair<int, int>
#define lowbit(x) (x & (-x))
int sz;
struct node
{int opt, v, x;
};
vector<int> e[N];
vector<int> path; // 记录dfs序
int idx[N]; // 节点u在path中的下标
int las[N]; // 节点u的子树在path中的最后截止位置
void dfs(int u)
{path.push_back(u);for (int v : e[u])dfs(v);las[u] = path.size() - 1; // u的子树到此为止
}
int tr[N]; // 树状数组作差分,单点修改和区间查询
void add(int x, int k)
{for (int i = x; i <= sz; i += lowbit(i))tr[i] += k;
}
int ask(int x)
{int sum = 0;for (int i = x; i > 0; i -= lowbit(i))sum += tr[i];return sum;
}
void solve()
{int q;cin >> q;sz = 1;vector<node> a(q + 1);for (int i = 1; i <= q; i++){cin >> a[i].opt;if (a[i].opt == 1){cin >> a[i].v;e[a[i].v].push_back(++sz);a[i].x = sz;}elsecin >> a[i].v >> a[i].x;}path.push_back(0);dfs(1);for (int i = 1; i < path.size(); i++)idx[path[i]] = i;vector<int> res(sz + 1, -1);for (int i = q; i >= 1; i--){if (a[i].opt == 1)res[a[i].x] = ask(idx[a[i].x]);elseadd(idx[a[i].v], a[i].x), add(las[a[i].v] + 1, -a[i].x);}res[1] = ask(1);for (int i = 1; i <= sz; i++)cout << res[i] << ' ';cout << endl;path.clear();for (int i = 1; i <= sz; i++){tr[i] = idx[i] = las[i] = 0;e[i].clear();}
}signed main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;cin >> t;while (t--)solve();
}