题目链接
感受
主
席
树
模
板
题
,
确
实
简
单
,
但
比
那
个
第
k
大
模
板
稍
微
难
一
点
主席树模板题,确实简单,但比那个第k大模板稍微难一点
主席树模板题,确实简单,但比那个第k大模板稍微难一点
思路
该
问
题
就
转
化
为
某
个
子
树
中
,
子
节
点
到
该
子
树
根
节
点
的
距
离
>
=
k
的
距
离
和
该问题就转化为某个子树中,子节点到该子树根节点的距离\\>=k的距离和
该问题就转化为某个子树中,子节点到该子树根节点的距离>=k的距离和
由
于
子
树
有
很
多
,
于
是
对
于
距
离
我
们
可
以
进
行
一
下
转
化
。
由于子树有很多,于是对于距离我们可以进行一下转化。
由于子树有很多,于是对于距离我们可以进行一下转化。
即
d
i
s
(
a
,
b
)
=
∣
d
i
s
(
a
,
1
)
−
d
i
s
(
b
,
1
)
∣
于
是
,
如
果
我
们
知
道
某
个
子
树
上
有
哪
些
节
点
,
并
把
这
些
节
点
单
独
处
理
,
可
以
做
一
棵
权
值
线
段
树
,
那
么
就
可
以
很
快
求
解
。
即dis(a, b)=|dis(a,1)-dis(b,1)|\\于是,如果我们知道某个子树上有哪些节点,并把这些节点\\单独处理,可以做一棵权值线段树,那么就可以很快求解。
即dis(a,b)=∣dis(a,1)−dis(b,1)∣于是,如果我们知道某个子树上有哪些节点,并把这些节点单独处理,可以做一棵权值线段树,那么就可以很快求解。
子
树
可
以
联
想
到
d
f
s
序
,
某
一
个
子
树
+
d
f
s
序
就
可
以
联
想
到
区
间
子树可以联想到dfs序,某一个子树+dfs序就可以联想到区间
子树可以联想到dfs序,某一个子树+dfs序就可以联想到区间
于
是
,
主
席
树
就
诞
生
了
。
于是,主席树就诞生了。
于是,主席树就诞生了。
我
们
可
以
先
求
出
这
棵
树
的
d
f
s
序
,
然
后
对
于
这
个
d
f
s
序
建
一
棵
主
席
树
,
其
中
每
个
节
点
维
护
到
该
时
刻
区
间
值
和
以
及
区
间
个
数
和
。
我们可以先求出这棵树的dfs序,然后对于这个dfs序建一棵\\主席树,其中每个节点维护到该时刻区间值和以及区间个数和。
我们可以先求出这棵树的dfs序,然后对于这个dfs序建一棵主席树,其中每个节点维护到该时刻区间值和以及区间个数和。
最
后
得
到
(
x
节
点
加
入
前
一
刻
,
x
节
点
子
树
加
完
的
最
后
一
刻
)
的
区
间
值
v
a
l
以
及
区
间
个
数
n
u
m
a
n
s
=
v
a
l
−
n
u
m
∗
d
i
s
[
x
]
最后得到(x节点加入前一刻,x节点子树加完的最后一刻)\\的区间值val以及区间个数num\\ans=val-num*dis[x]
最后得到(x节点加入前一刻,x节点子树加完的最后一刻)的区间值val以及区间个数numans=val−num∗dis[x]
总
体
来
说
就
是
,
d
f
s
序
上
建
一
棵
主
席
树
总体来说就是,dfs序上建一棵主席树
总体来说就是,dfs序上建一棵主席树
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
struct edge{
int v, nex; ll w;
}e[maxn << 1];
int head[maxn], cnt;
ll dis[maxn];
int in[maxn], out[maxn], a[maxn];///a[i] 表示dfs序中第i个点编号
ll sum[maxn << 5], num[maxn << 5];
int rt[maxn], lc[maxn << 5], rc[maxn << 5], tot;
vector<ll> b;
int n, now;
void add_edge(int u, int v, ll w){
e[cnt] = (edge){v, head[u], w};
head[u] = cnt++;
}
void init(){
cnt = 0;
for(int i = 1; i <= n; i++){
head[i] = -1;
}
}
void dfs(int u, int fa){
int v; ll w; in[u] = ++cnt; a[cnt] = u;
for(int i = head[u]; ~i; i = e[i].nex){
v = e[i].v; w = e[i].w;
if(v == fa) continue;
dis[v] = dis[u] + w;
dfs(v, u);
}
out[u] = cnt;
}
int get_id(ll x){
return lower_bound(b.begin(), b.end(), x) - b.begin() + 1;
}
void build(int &o, int l, int r){
o = ++tot; sum[o] = 0; num[o] = 0;
if(l == r) return ;
int mid = (l + r) / 2;
build(lc[o], l, mid);
build(rc[o], mid + 1, r);
}
int update(int o, int l, int r, int k){
int oo = ++tot; sum[oo] = sum[o] + b[k - 1]; num[oo] = num[o] + 1;
lc[oo] = lc[o], rc[oo] = rc[o];
if(l == r) return oo;
int mid = (l + r) / 2;
if(mid >= k) lc[oo] = update(lc[o], l, mid, k);
else rc[oo] = update(rc[o], mid + 1, r, k);
return oo;
}
void query(int loo, int roo, int l, int r, int x, int y, ll &ans, ll &gg){
if(l >= x && y >= r){
ans += sum[roo] - sum[loo]; gg += num[roo] - num[loo];
return ;
}
int mid = (l + r) / 2;
if(mid >= x) query(lc[loo], lc[roo], l, mid, x, y, ans, gg);
if(y > mid) query(rc[loo], rc[roo], mid + 1, r, x, y, ans, gg);
}
void print(int o, int l, int r){
printf("[%d, %d] = %lld\n", l, r, sum[o]);
if(l == r) return ;
int mid = (l + r) / 2;
print(lc[o], l, mid);
print(rc[o], mid + 1, r);
}
int main(){
scanf("%d", &n);
init();
int p; ll d;
for(int i = 1; i < n; i++){
scanf("%d%lld", &p, &d);
add_edge(p, i + 1, d); add_edge(i + 1, p, d);
}
dis[1] = cnt = 0;
dfs(1, 0);
for(int i = 1; i <= n; i++){
b.push_back(dis[i]);
}
sort(b.begin(), b.end()); b.erase(unique(b.begin(), b.end()), b.end());
now = b.size();
build(rt[0], 1, now);
for(int i = 1; i <= n; i++){
int pos = get_id(dis[a[i]]);
rt[i] = update(rt[i - 1], 1, now, pos);
}
int q, x, k;
scanf("%d", &q);
while(q--){
scanf("%d%lld", &x, &d);
d += dis[x];
k = get_id(d);///[k, now]
if(k > now) puts("0");
else{
ll ans = 0, gg = 0;
query(rt[in[x] - 1], rt[out[x]], 1, now, k, now, ans, gg);
printf("%lld\n", ans - gg * dis[x]);
}
}
return 0;
}
/*
5
1 5
2 3
2 4
1 10
100
5 0
*/