大致题意就是:dfs 时,在子树里查询权值大于 k 的子节点的权值和,然后要在子树里每个节点都加上一个 w(每次加的不一样)。然后把子树合并。
我的想法:在子树里以权值 k−1 split 一下,然后把大于等于 k 的那个根的 sum 输出。之后启发式合并每个子树。
遇到的问题是:在输出答案的时候时对时错,输出树的中序遍历发现权值不单调增加。
可能的猜测:维护权值和打标记或者传标记的时候出现了问题,导致合并的时候出锅了。
输入格式:对于 2 到 n 每个节点读入 fai 和 wi,wi 是要加到子树所有节点的那个值。之后是离线了询问,查询的就是题意里的东西。
extra:还想问一下大佬们这种题调试的时候都要输出什么啊。
感谢看我这么多字和毒瘤代码。。
代码:
#include <bits/stdc++.h>
using namespace std;
#define p pair<int, int>
typedef vector<p>::iterator iter;
typedef long long ll;
const int N = 2e5 + 10;
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
vector<p> v[N], query[N];
int sz[N], pri[N], ch[N][2];
int cnt, root[N];
ll ans[N], val[N], sum[N], tag[N];
void get(int x) { // 中序遍历
if (!x) return;
get(ls(x));
cerr << val[x] << " ";
get(rs(x));
}
inline void pushup(int x) {
sz[x] = sz[ls(x)] + sz[rs(x)] + 1;
sum[x] = sum[ls(x)] + sum[rs(x)] + val[x];
}
inline void add(int x, ll w) { // 加标记
val[x] += w, sum[x] += w * sz[x], tag[x] += w;
}
inline void pushdown(int x) {
if (tag[x]) {
if (ls(x)) add(ls(x), tag[x]);
if (rs(x)) add(rs(x), tag[x]);
tag[x] = 0;
}
}
inline int newNode(int w) {
sz[++cnt] = 1, val[cnt] = sum[cnt] = w, pri[cnt] = rand();
return cnt;
}
void split(int now, ll w, int &x, int &y) {
if (!now) {
x = y = 0;
} else {
pushdown(now);
if (val[now] <= w) {
x = now, split(rs(now), w, rs(now), y);
} else {
y = now, split(ls(now), w, x, ls(now));
}
pushup(now);
}
}
int merge(int x, int y) {
if (!x || !y) return x | y;
if (pri[x] < pri[y]) {
pushdown(x);
rs(x) = merge(rs(x), y);
return pushup(x), x;
} else {
pushdown(y);
ls(y) = merge(x, ls(y));
return pushup(y), y;
}
}
int cass;
void insert(int &root, int x) {
int a, b;
ll v = val[x];
split(root, v, a, b);
root = merge(merge(a, x), b);
}
void transform(int x, int &y) { // 递归进行启发式合并
if (!x) return;
transform(ls(x), y), transform(rs(x), y);
ls(x) = rs(x) = 0;
insert(y, x);
}
int treeMerge(int x, int y) {
if (sz[x] > sz[y]) swap(x, y);
return transform(x, y), y;
}
ll queryAns(int &x, ll w) { // 查询答案
int a, b;
ll ans;
split(x, w - 1, a, b);
ans = sum[b];
x = merge(a, b);
return ans;
}
void dfs(int x) {
root[x] = newNode(0);
for (iter it = v[x].begin(); it != v[x].end(); ++it) {
// it->first是到的节点
// it->second是要给子树加上的权值
dfs(it->first);
add(root[it->first], it->second);
root[x] = treeMerge(root[x], root[it->first]);
}
for (iter it = query[x].begin(); it != query[x].end(); ++it) {
// it->first是要查询的值k
// it->second是查询的编号(离线用)
ans[it->second] = queryAns(root[x], it->first);
}
}
int n, q;
int main() {
srand(20040410), read(n);
for (int i = 2, x, y; i <= n; ++i)
read(x), read(y), v[x].push_back(p(i, y));
read(q);
for (int i = 1, u, k; i <= q; ++i) {
read(u), read(k);
query[u].push_back(p(k, i));
}
dfs(1);
for (int i = 1; i <= q; ++i) { write(ans[i]), putchar('\n'); }
}