链接:https://ac.nowcoder.com/acm/problem/14415
来源:牛客网
题目描述
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<=2x105,1<=D,K<=106)
输出描述:
对于每次询问x,k输出以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。(若不存在这样的点,则输出应为0)
示例1
输入
3
1 2
1 3
2
1 3
1 2
输出
3
5
思路:
子树问题很容易想到通过dfs序转化为序列的区间问题
区间问题很容易想到主席树
所以这题就用dfs序建主席树来解
主席树维护每个节点为根到x的距离dist[x]的cnt和sum
询问就变为:
区间中距离根的距离大于等于dist[x]+k的和减掉cnt*dist[x]
还有就是查询的时候直接查询r[L[x]]到r[R[x]],L[x]不用减1
因为边权附在下面的点上了(如果是点权好像要减)
ps:
因为爆int,所以很多地方要改longlong
但是直接define int longlong 超内存了
然后手动修改的时候会漏掉很多地方(比如mid等等)
结果就是一直wa
有毒
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const int maxm=2e5+5;
const int M=maxm*2;
int head[maxm],nt[M],to[M],cnt;
ll w[M];
int L[maxm],R[maxm];
ll dist[maxm];
int n,q;
ll ma;//线段树最大范围1-ma
struct Node{
int lc,rc;
ll cnt,sum;
}a[maxm*40];
int r[maxm],tot;
void init(){
memset(head,-1,sizeof head);
cnt=1;
tot=0;
}
void add(int x,int y,int z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
}
void update(int &k,ll x,ll l,ll r,int last){
k=tot++;
a[k]=a[last];
a[k].sum+=x;
a[k].cnt++;
if(l==r)return ;
ll mid=(l+r)/2;
if(x<=mid)update(a[k].lc,x,l,mid,a[last].lc);
else update(a[k].rc,x,mid+1,r,a[last].rc);
}
void dfs(int x,int fa,ll val){
L[x]=++cnt;
dist[x]=val;
update(r[cnt],dist[x],1,ma,r[cnt-1]);
for(int i=head[x];i!=-1;i=nt[i]){
int v=to[i];
if(v==fa)continue;
dfs(v,x,val+w[i]);
}
R[x]=cnt;
}
ll anscnt,anssum;
void ask(ll st,ll ed,ll l,ll r,int x,int y){
if(st<=l&&ed>=r){
anscnt+=a[y].cnt-a[x].cnt;
anssum+=a[y].sum-a[x].sum;
return ;
}
ll mid=(l+r)/2;
if(st<=mid){
ask(st,ed,l,mid,a[x].lc,a[y].lc);
}
if(ed>=mid+1){
ask(st,ed,mid+1,r,a[x].rc,a[y].rc);
}
}
signed main(){
init();
scanf("%d",&n);
for(int i=1;i<n;i++){
int p,d;
scanf("%d%d",&p,&d);
add(p,i+1,d);
add(i+1,p,d);
ma+=d;
}
cnt=0;
dfs(1,-1,0);
int q;
scanf("%d",&q);
while(q--){
int x;
ll k;
scanf("%d%lld",&x,&k);
k+=dist[x];
anscnt=anssum=0;
ask(k,ma,1,ma,r[L[x]],r[R[x]]);
printf("%lld\n",anssum-anscnt*dist[x]);
}
return 0;
}