树的距离

树的距离

题目大意: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 }
View Code
原文地址:https://www.cnblogs.com/CJLHY/p/7895286.html