题意:

  设 T 为一棵有根树,我们做如下的定义:

  • 设 a 和 b 为 T 中的两个不同节点。如果 a 是 b 的祖先,那么称“a 比 b 不知道高明到哪里去了”。

  • 设 a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定常数 x,那么称“a 与 b 谈笑风生”。

给定一棵 n 个节点的有根树 T,节点的编号为 1 ∼ n,根节点为 1 号节点。你需要回答 q 个询问,询问给定两个整数 p 和 k,问有多少个有序三元组 (a; b; c) 满足:

  1. a、 b 和 c 为 T 中三个不同的点,且 a 为 p 号节点;

  2. a 和 b 都比 c 不知道高明到哪里去了;

  3. a 和 b 谈笑风生。这里谈笑风生中的常数为给定的 k。

分析:

  这道题目,也许是出题人有意地把题目描述复杂化了。实际上这并不是一道难题,甚至达不到近年来省选的难度。

  但是这确实是一道值得交流的题目,我见过的这道题就有不下五种做法,有在线的,有离线的,我用的是在线的主席树维护dfs序的方法。我开始以为这道题让求的是这样的有序三元组的数目,感觉十分不可做,后来发现,a点是已经固定的。

  我们不考虑什么“高明到哪里去了”,三元组的要求是说,给出a,求点a和点b都在c到根的路径上,也就是都是c的祖先,并且a和b距离不超过k的(a,b)数目。

  因为a和b在c的父链上这个限制,我们可以分类讨论,如果b也在a的父链上,那么应该很好求,就是这条链上深度和a相差不超过k的点数目,乘上(a的子树size-1)(减一是因为a自己不算),这就是一个简单的乘法原理,预处理了O(1)就能求出。

  然后是假如b本身就存在于a的一个子树中,距离不超过k,我们知道,一棵子树,在dfs序上是连续的,所以我们在预处理是,以dfs序为版本,以深度为区间,以子树大小为权值建主席树(原因是因为此时我只需要控制深度差范围内的所有贡献,并不一定要知道是具体哪个点的贡献,所以深度一样我们通通加到一个主席树节点权值里)。

  查询?很好说了吧,只要我们知道深度差的范围和这个点对应的子树dfs序区段。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=300005,inf=1e9;
 5 struct node{int y,nxt;}e[N*2];
 6 int n,m,md,h[N],c=0,d[N],sz[N];
 7 int rt[N],cnt,tot,dfn[N],fa[N];
 8 struct ch{int l,r;ll da;}t[N*30];
 9 void add(int x,int y){
10     e[++c]=(node){y,h[x]};h[x]=c;
11     e[++c]=(node){x,h[y]};h[y]=c;
12 } void dfs1(int x){sz[x]=1;
13     for(int i=h[x],y;i;i=e[i].nxt)
14     if(!d[y=e[i].y]){
15         d[y]=d[x]+1;md=max(md,d[y]);
16         fa[y]=x;dfs1(y);sz[x]+=sz[y];
17     } return ;
18 } void update(int &x,int l,int r,ll v,int p){
19     t[++cnt]=t[x];x=cnt;t[x].da+=v;
20     if(l==r) return;int mid=l+r>>1;
21     if(p<=mid) update(t[x].l,l,mid,v,p);
22     else update(t[x].r,mid+1,r,v,p);
23 } ll query(int x,int y,int l,int r,int L,int R){
24     if(L<=l&&r<=R) return t[y].da-t[x].da;
25     int mid=l+r>>1;ll re=0;
26     if(L<=mid)re+=query(t[x].l,t[y].l,l,mid,L,R);
27     if(mid<R)re+=query(t[x].r,t[y].r,mid+1,r,L,R);
28     return re;
29 } void dfs2(int x){
30     dfn[x]=++tot;rt[tot]=rt[tot-1];
31     update(rt[tot],1,md,sz[x]-1,d[x]);
32     for(int i=h[x],y;i;i=e[i].nxt){
33         if((y=e[i].y)==fa[x]) continue;
34         dfs2(y);
35     } return ;
36 } int main(){
37     scanf("%d%d",&n,&m);
38     for(int i=1,x,y;i<n;i++)
39     scanf("%d%d",&x,&y),add(x,y);
40     d[1]=1;dfs1(1);dfs2(1);
41     for(int i=1;i<=m;i++){
42         int p,k;scanf("%d%d",&p,&k);
43         ll ans=(sz[p]-1)*1ll*(min(k,d[p]-1));
44         int l=dfn[p]-1,r=dfn[p]+sz[p]-1;
45         if(d[p]==md){puts("0");continue;}
46         int z=min(md,d[p]+k);
47         ans+=query(rt[l],rt[r],1,md,d[p]+1,z);
48         printf("%lld\n",ans);
49     } return 0;
50 }

主席树

转载于:https://www.cnblogs.com/Alan-Luo/p/10192070.html

[湖南集训] 谈笑风生相关推荐

  1. 洛谷 - P3899 [湖南集训]谈笑风生(dfs序+主席树/二维数点)

    题目链接:点击查看 题目大意:设 TTT 为一棵有根树,我们做如下的定义: 设 aaa 和 bbb 为 TTT 中的两个不同节点.如果 aaa 是 bbb 的祖先,那么称"aaa 比 bbb ...

  2. P3899 [湖南集训]谈笑风生(线段树合并)

    P3899 [湖南集训]谈笑风生 给定一颗以111号节点为根的树,如果a≠ba \neq ba​=b,且aaa是bbb的祖先,则aaa比bbb更厉害,如果a≠ba \neq ba​=b,且dis( ...

  3. P3899 [湖南集训]谈笑风生

    P3899 [湖南集训]谈笑风生 题目描述 Solution 我们考虑离线询问,将询问放在相对应的子树ppp中计算答案. 显然a,b,ca,b,ca,b,c的位置关系有两种情况: bbb是aaa的祖先 ...

  4. 洛谷P3899 [湖南集训]谈笑风生

    Description 设T 为一棵有根树,我们做如下的定义: • 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称"a比b不知道 高明到哪里去了". • 设a 和 b 为 ...

  5. luogu P3899 [湖南集训]谈笑风生 线段树合并

    Description 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称"a比b不知道 高明到哪里去了". ? 设a 和 b 为 ...

  6. [湖南集训]谈笑风生

    谈笑风生 题目大意: 给定a,求任何一个距 a 距离不超过给定的 k 的 b ,然后求一个 c 使得其为 a,b 的后代,求这样的三元组共有多少个. 数据结构好题啊! 解法分析: 我们可以深搜两遍(其 ...

  7. bzoj 3653 [湖南集训]谈笑风生

    题目描述 设 T 为一棵有根树,我们做如下的定义: • 设 a 和 b 为 T 中的两个不同节点.如果 a 是 b 的祖先,那么称"a 比 b 不知道高明到哪里去了". • 设 a ...

  8. P3899 [湖南集训]谈笑风生 主席树解决二维数点

    传送门 文章目录 题意: 思路: 题意: 思路: 由于a,ba,ba,b都比ccc厉害,那么a,ba,ba,b一定是某个是某个的祖先.那么就分为两种情况了: (1)(1)(1) bbb在aaa上面,约 ...

  9. [主席树] 湖南集训 谈笑风生

    传送门 一.做法 CCC一定是A,BA, BA,B公共子树里的点 B在A上方 则C一定在A子树中 ans=min⁡{k,dep[A]−1}×(siz[A]−1)ans=\min\{k,dep[A]-1 ...

最新文章

  1. python五十五:__getattribute__内置函数
  2. 无线通信 -- 跳频技术
  3. ERROR: No matching distribution found for onnxsim
  4. 成功解决TypeError: ‘encoding’ is an invalid keyword argument for this function
  5. 文献记录(part1)--NP-hardness of Euclidean sum-of-squares clustering
  6. python 回溯法 子集树模板 系列 —— 1、8 皇后问题
  7. 数据预处理和特征工程
  8. saltstack mysql_saltstack学习五:return及入库_MySQL
  9. american fuzzy lop 介绍
  10. 【MySQL】mysql死锁以及死锁日志分析
  11. vue 上下滚动的菜单_vue实现广告栏上下滚动效果
  12. 信鸽 ios tag推送 php,信鸽推送集成
  13. 2019-成长的一年
  14. python协程处理海量文件_Python使用asyncio和run-In-Executor线程池处理多个文件的同时下载,python,协程,加,runinexecutor...
  15. 三线性插值(Trilinear Interpolation)详解
  16. 使用C#启动默认Internet浏览器
  17. c语言实现在数组中找一个数字显示,C语言找出数组中的特定元素的算法解析
  18. 使用GNURadio和RTL-SDR搭建FM广播接收机
  19. 【Linux】安装 Ubuntu18.04 全程实录(安装 NVIDIA 驱动,安装主题美化,安装应用程序,网易云无法启动,GoldenDict 音标显示不正常)
  20. Poker 键盘试用

热门文章

  1. Tricks Device 最短路+最大流
  2. python列表内元素求和_Python之list对应元素求和
  3. Java常用算法二:分治法
  4. C++11新特性之 可变参数模板
  5. TCP和UDP的不同
  6. bzoj 1664: [Usaco2006 Open]County Fair Events 参加节日庆祝(DP)
  7. [paper reading] YOLO v1
  8. 最新高清IT职业技能图谱(15图)
  9. matlab2c使用c++实现matlab函数系列教程-histc函数
  10. python递归的方式打印九九乘法表