题目大意:wyf非常喜欢树。一棵有根数树上有N个节点,1号点是他的根,每条边都有一个距离,而wyf是个爱问奇怪问题的熊孩子,他想知道对于某个点x,以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。N<=2e5
思路:可以考虑离线算法,我们先将树dfs一遍,我们按dfs序在w中保存各个节点的深度的和序号,L[x],R[x],dis[x]分别表示以x为根的子树对应的dfs序的左右端点,以及x的深度。对每个操作q我们记录子树根节点,和v值,v=dis[x]+k。然后我们将w按节点深度从大到小排序,q按v值从大到小排序。开两个树状数组,第一个记录已经加入的节点的个数的前缀和,另一个记录已加入节点的深度的前缀和。 遍历操作q,将比q.v大或相等的节点的加入到两个树状数组中,我们再查询以q.x对应的dfs序的左右端点之间一共有多少个点cnt,和这些点的深度和是多少sum,那么这次操作的答案就是sum-cnt*dis[q.x]。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N=2*1e5+5; 5 int n,m,head[N],tot,top,L[N],R[N]; 6 ll bit[2][N],dis[N],ans[N]; 7 struct edge 8 { 9 int f,t,next; ll v; 10 }e[N]; 11 struct node 12 { 13 int id; ll v; 14 bool operator <(const node &rhs)const 15 { 16 return v>rhs.v; 17 } 18 }w[N]; 19 struct query 20 { 21 int id,x; ll v; 22 bool operator <(const query &rhs)const 23 { 24 return v>rhs.v; 25 } 26 }q[N]; 27 void add(int f,int t,ll v) 28 { 29 e[tot].f=f; e[tot].t=t; e[tot].v=v; 30 e[tot].next=head[f]; head[f]=tot++; 31 } 32 void update(int x,ll v,int op) 33 { 34 while(x<N) 35 { 36 bit[op][x]+=v; 37 x+=x&(-x); 38 } 39 } 40 ll query(int x,int op) 41 { 42 ll ans=0; 43 while(x>0) 44 { 45 ans+=bit[op][x]; 46 x-=x&(-x); 47 } 48 return ans; 49 } 50 void dfs(int v,int p,ll d) 51 { 52 dis[v]=d; 53 L[v]=++top; 54 w[top].v=d; w[top].id=top; 55 for(int i=head[v];~i;i=e[i].next) 56 { 57 int nx=e[i].t; 58 if(dis[nx]) continue; 59 dfs(nx,v,d+e[i].v); 60 } 61 R[v]=top; 62 } 63 int main() 64 { 65 memset(head,-1,sizeof(head)); tot=top=0; 66 scanf("%d",&n); 67 for(int i=2;i<=n;i++) 68 { 69 int P; ll D; 70 scanf("%d%lld",&P,&D); 71 add(P,i,D); 72 } 73 dfs(1,0,1); 74 scanf("%d",&m); 75 for(int i=1;i<=m;i++) 76 { 77 int x; ll k; scanf("%d%lld",&x,&k); 78 q[i].x=x; q[i].v=dis[x]+k; 79 q[i].id=i; 80 } 81 sort(w+1,w+1+n); 82 sort(q+1,q+1+m); 83 int j=1; 84 for(int i=1;i<=m;i++) 85 { 86 for(;w[j].v>=q[i].v && j<=n;j++) 87 { 88 update(w[j].id,1,0); 89 update(w[j].id,w[j].v,1); 90 } 91 ll cnt=query(R[q[i].x],0)-query(L[q[i].x]-1,0); 92 ll sum=query(R[q[i].x],1)-query(L[q[i].x]-1,1); 93 ans[q[i].id]=sum-cnt*dis[q[i].x]; 94 } 95 for(int i=1;i<=m;i++) printf("%lld ",ans[i]); 96 return 0; 97 }