传送门
题目描述:
wyf非常喜欢树。一棵有根数树上有N个节点,1号点是他的根,每条边都有一个距离,而wyf是个爱问奇怪问题的熊孩子,他想知道对于某个点x,以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。
输入描述:
第一行一个正整数N
接下来N-1描述这棵树,每行两个数第i行两个数p和D表示树上有一条p到i+1长度为D的边。(p<=i)
下面一行一个正整数Q表示wyf的询问次数。
接下来Q行每行两个正整数x和k。 (1<=N,Q<=2x10^5,1<=D,K<=10^6)
输出描述:
对于每次询问x,k输出以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。(若不存在这样的点,则输出应为0)
解题思路: 题目上询问的是子树上的点,很容易想到DFS序,因为要用到时间戳,就想到了可持久化线段树。。
因为一棵子树的DFS序恰好是一个区间,利用可持久化线段树就很容易查询了。
维护 区间所有值的和 和 结点的个数,询问时答案 = 距离大于等于 dis[x]+k 所有值的和 - cnt * dis[ x ]。
代码:
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a, b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai = acos(-1.0);
const double E = 2.718281828459;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 10;
int root[maxn], times; /// 根结点 动态树时间戳
int head[maxn], sign; /// 边
int in[maxn], out[maxn], t; /// DFS序
ll dis[maxn]; ///距离根节点的距离
struct node {
int ls, rs;
ll cnt, sum;
} p[maxn * 40];
struct node_e {
int e;
ll c;
int p;
} load[maxn << 1];
void add_edge(int s, int e, ll c) {
load[++sign] = node_e{e, c, head[s]};
head[s] = sign;
}
void insert(int &now, int old, ll l, ll r, ll x) {
now = ++times;
p[now] = p[old], p[now].sum += x, p[now].cnt++;
if (l == r)
return;
ll mid = (l + r) >> 1LL;
if (x <= mid) insert(p[now].ls, p[old].ls, l, mid, x);
else insert(p[now].rs, p[old].rs, mid + 1, r, x);
}
ll sum_dis, sum_cnt;
void query(int sta, int end, ll l, ll r, ll x) {
if (l >= x) {
sum_dis += p[end].sum - p[sta].sum;
sum_cnt += p[end].cnt - p[sta].cnt;
return;
}
ll mid = (l + r) >> 1;
if (x <= mid) {
sum_dis += p[p[end].rs].sum - p[p[sta].rs].sum;
sum_cnt += p[p[end].rs].cnt - p[p[sta].rs].cnt;
query(p[sta].ls, p[end].ls, l, mid, x);
} else
query(p[sta].rs, p[end].rs, mid + 1, r, x);
}
void dfs(int s, int pre) {
in[s] = ++t;
insert(root[t], root[t - 1], (ll) 1, (ll) 1e11, dis[s]);
for (int i = head[s], e; ~i; i = load[i].p) {
e = load[i].e;
if (e ^ pre) {
dis[e] = dis[s] + load[i].c;
dfs(e, s);
}
}
out[s] = t;
}
void init() {
t = times = sign = 0;
memset(head, -1, sizeof(head));
memset(p, 0, sizeof(p));
memset(root, 0, sizeof(root));
memset(dis, 0, sizeof(dis));
}
int main() {
init();
int n, op, s, x;
ll c, k;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d %lld", &s, &c);
add_edge(s, i + 1, c);
add_edge(i + 1, s, c);
}
dfs(1, -1);
scanf("%d", &op);
while (op--) {
sum_cnt = sum_dis = 0;
scanf("%d %lld", &x, &k);
k = k + dis[x];
query(root[in[x]], root[out[x]], 1LL, (ll) 1e11, k);
printf("%lld\n", sum_dis - sum_cnt * dis[x]);
}
}