树的距离

树的距离

题目大意: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\n",ans[i]);
96     return 0;
97 }

时间: 2024-08-09 19:57:46

树的距离的相关文章

51 nod 1405 树的距离之和

1405 树的距离之和 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和. Input 第一行包含一个正整数n (n <= 100000),表示节点个数. 后面(n - 1)行,每行两个整数表示树的边. Output 每行一个整数,第i(i = 1,2,...n)行表示所有节点到第i个点的距离之和. Input示例 4 1 2 3 2 4 2 Output示例 5 3 5

51Nod 1405 树的距离之和(dp)

1405 树的距离之和 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和. Input 第一行包含一个正整数n (n <= 100000),表示节点个数. 后面(n - 1)行,每行两个整数表示树的边. Output 每行一个整数,第i(i = 1,2,...n)行表示所有节点到第i个点的距离之和. Input示例 4 1 2 3 2 4 2 Output

[51NOD1405] 树的距离之和(树DP)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1405 (1)我们给树规定一个根.假设所有节点编号是0-(n-1),我们可以简单地把0当作根,这样下来父子关系就确定了. (2)定义数组num[x]表示以节点x为根的子树有多少个节点,dp[x]是我们所求的--所有节点到节点x的距离之和. (3)在步骤(1)中,其实我们同时可以计算出 num[x],还可以计算出每个节点的深度(每个到根节点0的距离),累加全部节点

BZOJ 2735: 世博会 主席树+切比雪夫距离转曼哈顿距离

2735: 世博会 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 124  Solved: 51[Submit][Status][Discuss] Description 四年一度的世博会又要举办了,Q国很荣幸成为了这次世博会的主办方.Q国主席QQ从全国各地收集了N件物品排成 一排,作为Q国馆的展出物.对于相邻摆放的一些物品,如果过于相似会让人觉得无聊,如果差别过大又会让人觉 得突兀.为了让人们对这次世博会的展出满意,QQ需要知道一些相邻物品的“

wannafly挑战赛4树的距离 离线处理,dfs序

时间限制:C/C++ 2秒,其他语言4秒空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 wyf非常喜欢树.一棵有根数树上有N个节点,1号点是他的根,每条边都有一个距离,而wyf是个爱问奇怪问题的熊孩子,他想知道对于某个点x,以x为根的子树上,所有与x距离大于等于k的点与x的距离之和. 输入描述: 第一行一个正整数N 接下来N-1描述这棵树,每行两个数第i行两个数p和D表示树上有一条p到i+1长度为D的边.(p<=i) 下面一行一

51Nod 1405 树的距离之和 (dfs)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1405 中文题面不解释了,两次dfs,第一次自下向上,第二次自上向下. ans[i]表示i节点的答案,cnt[i]表示i节点为root的子树的节点个数,d[i]表示i节点为root的子树的答案. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algor

左偏树

概要:左偏树是具有左偏性质的堆有序二叉树,它相比于优先队列,能够实现合并堆的功能. 先仪式型orzorzozr国家集训队论文https://wenku.baidu.com/view/515f76e90975f46527d3e1d5.html 左偏树的节点定义: 1 struct node { 2 int lc, rc, val, dis; 3 } LTree[maxn]; 左偏树的几个基本性质如下: 节点的键值小于等于它的左右子节点的键值 节点的左子节点的距离不小于右子节点的距离 节点的距离等于

图论-树的最大路

历届试题 大臣的旅费 时间限制:1.0s   内存限制:256.0MB 问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达.同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的. J是T国重要大臣,他巡查于各大城市之间,体察民情.所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情.他有一个钱袋,用于

左偏树(可并堆)

"左偏"树? 左偏树其实是一种可并堆,它可以 \(O(log_2 n)\) 合并两个堆. 那左偏?也就是说他左边肯定有什么东西比右边大-- 别着急,在左偏树上有一个叫距离的东西: 个点的距离,被定义为它子树中离他最近的外节点到这个节点的距离(这与树的深度不同) 其中我们定义一个节点为外节点,当且仅当这个节点的左子树和右子树中的一个是空节点.(注意外节点不是叶子节点) 这幅图中的这三个节点都是外节点. 而左偏树指的就是就是一个节点的左儿子的距离一定大于等于右儿子的距离. 例如下面就是一棵