链接:

https://www.spoj.com/problems/COT/en/

思路:

首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们可以用dfs跑出所有点离根的距离-dep[i](根为1,dep[1]也为1)在dfs的过程

中,我们对每一个节点建一棵线段树,那么【a,b】就是:root[a] + root[b] - root[lca(a,b)] - root[f[lca(a,b)]]; (因为a-b的路径上的权值还要算上lca(a,b)这个点,所以不是减2*root[lca(a,b)]);

实现代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define lson l,m,rt<<1
  5. #define rson m+1,r,rt<<1|1
  6. #define mid int m = (l + r) >> 1
  7. const int M = 2e5 + ;
  8. int p[M][],dep[M],head[M],sum[M*],ls[M*],rs[M*],root[M*];
  9. int cnt1,n,idx,cnt,f[M];
  10.  
  11. struct node {
  12. int to,next;
  13. }e[M];
  14.  
  15. void add(int u,int v){
  16. e[++cnt1].to=v;e[cnt1].next=head[u];head[u]=cnt1;
  17. e[++cnt1].to=u;e[cnt1].next=head[v];head[v]=cnt1;
  18. }
  19.  
  20. int lca(int a,int b){
  21. if(dep[a] > dep[b]) swap(a,b);
  22. int h = dep[b] - dep[a]; //h为高度差
  23. for(int i = ;(<<i)<=h;i++){ //(1<<i)&f找到h化为2进制后1的位置,移动到相应的位置
  24. if((<<i)&h) b = p[b][i];
  25. //比如h = 5(101),先移动2^0祖先,然后再移动2^2祖先
  26. }
  27. //cout<<a<<" "<<b<<endl;
  28. if(a!=b){
  29. for(int i = ;i >= ;i --){
  30. if(p[a][i]!=p[b][i]){ //从最大祖先开始,判断a,b祖先,是否相同
  31. a = p[a][i]; b = p[b][i]; //如不相同,a,b,同时向上移动2^j
  32. }
  33. }
  34. a = p[a][]; //这时a的father就是LCA
  35. }
  36. return a;
  37. }
  38.  
  39. void build(int l,int r,int &rt){
  40. rt = ++idx;
  41. sum[rt] = ;
  42. if(l == r) return;
  43. mid;
  44. build(l,m,ls[rt]);
  45. build(m+,r,rs[rt]);
  46. }
  47.  
  48. void update(int p,int l,int r,int old,int &rt){
  49. rt = ++idx;
  50. ls[rt] = ls[old]; rs[rt] = rs[old]; sum[rt] = sum[old] + ;
  51. if(l == r) return ;
  52. mid;
  53. if(p <= m) update(p,l,m,ls[old],ls[rt]);
  54. else update(p,m+,r,rs[old],rs[rt]);
  55. }
  56.  
  57. int query(int a,int b,int lc,int cl,int l,int r,int k){
  58. if(l == r) return l;
  59. mid;
  60. int cnt = sum[ls[a]] + sum[ls[b]] - sum[ls[lc]] - sum[ls[cl]];
  61. if(k <= cnt)
  62. return query(ls[a],ls[b],ls[lc],ls[cl],l,m,k);
  63. else
  64. return query(rs[a],rs[b],rs[lc],rs[cl],m+,r,k-cnt);
  65. }
  66. int a[M],b[M];
  67.  
  68. void dfs(int u,int fa){
  69. f[u] = fa;
  70. dep[u] = dep[fa] + ;
  71. p[u][] = fa;
  72. for(int i = ;i < ;i ++) p[u][i] = p[p[u][i-]][i-];
  73. update(a[u],,cnt,root[fa],root[u]);
  74. for(int i = head[u];i!=-;i = e[i].next){
  75. int v = e[i].to;
  76. if(v == fa) continue;
  77. dfs(v,u);
  78. }
  79. }
  80.  
  81. int main()
  82. {
  83. int m;
  84. while(scanf("%d%d",&n,&m)!=EOF){
  85. cnt1 = ;
  86. memset(head,-,sizeof(head));
  87. memset(dep,,sizeof(dep));
  88. memset(p,,sizeof(p));
  89. memset(f,,sizeof(f));
  90. for(int i = ; i <= n;i ++){
  91. scanf("%d",&a[i]);
  92. b[i] = a[i];
  93. }
  94. idx = ;
  95. int l,r,c;
  96. sort(b+,b+n+);
  97. cnt = unique(b+,b++n)-b-;
  98. for(int i = ;i <= n;i ++)
  99. a[i] = lower_bound(b+,b+cnt+,a[i]) - b;
  100. for(int i = ;i <= n-;i ++){
  101. scanf("%d%d",&l,&r);
  102. add(l,r);
  103. }
  104. build(,cnt,root[]);
  105. dfs(,);
  106. for(int i = ;i <= m;i ++){
  107. scanf("%d%d%d",&l,&r,&c);
  108. int lc = lca(l,r);
  109. int id = query(root[l],root[r],root[lc],root[f[lc]],,cnt,c);
  110. printf("%d\n",b[id]);
  111. }
  112. }
  113. return ;
  114. }

spoj COT - Count on a tree (树上第K小 LCA+主席树)的更多相关文章

  1. E - Count on a tree 树上第K小

    主席树的入门题目,这道题的题意其实就是说,给你一棵树,询问在两个节点之间的路径上的区间第K小 我们如何把树上问题转换为区间问题呢? 其实DFS就可以,我们按照DFS的顺序,对线段树进行建树,那么这个树 ...

  2. SPOJ - COT Count on a tree

    地址:http://www.spoj.com/problems/COT/en/ 题目: COT - Count on a tree #tree You are given a tree with N  ...

  3. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  4. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  5. SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解

    题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...

  6. spoj cot: Count on a tree 主席树

    10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...

  7. SPOJ 10628. SPOJ COT Count on a tree 可持久化线段树

    这题是裸的主席树,每个节点建一棵主席树,再加个lca就可以了. 历尽艰辛,终于A掉了这一题,这般艰辛也显示出了打代码的不熟练. 错误:1.lca倍增的时候i和j写反了,RE了5次,实在要吸取教训 2. ...

  8. spoj COT - Count on a tree(主席树 +lca,树上第K大)

    您将获得一个包含N个节点的树.树节点的编号从1到Ñ.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数Ñ和中号.( ...

  9. SPOJ 10628 COT - Count on a tree(在树上建立主席树)(LCA)

    COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...

随机推荐

  1. 重度使用示波器进行优化分析——一个DSDA项目回顾

    这是若干年前一个项目,最近有时间整理一下.回忆起来,印象最深刻的就是重度使用示波器辅助分析,进行优化. 项目背景是在原有项目3G+项目基础上,增加一颗2G+ Modem,使支持DSDA功能. 在介绍D ...

  2. [04] 高级映射 association和collection

    之前我们提到的映射,都是简单的字段和对象属性一对一,假设对象的属性也是一个对象,即涉及到两个表的关联,此时应该如何进行映射处理? 先看两张表,author 和 book:    业务上对应关系为,一个 ...

  3. 请允许我转载一篇关于套接字的博客:Socket

    这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...

  4. 51nod 抽卡大赛

    抽卡大赛 链接 分析: $O(n^4)$的做法比较好想,枚举第i个人选第j个,然后背包一下,求出有k个比他大的概率. 优化: 第i个人,选择一张卡片,第j个人选的卡片大于第i个人的概率是$p_j$,那 ...

  5. java基础(个人学习笔记) A

    1.       声明long类型的变量 需要在数值的末尾+l/L.(不加L的话,貌似默认就是int型了.当给long赋值一个超过int范围的值的时候,会出问题.) 2.  package java_ ...

  6. Vue2.0 搭配 axios

    1.安装axios $ npm install axios 2.Demo (1)Get // 为给定 ID 的 user 创建请求 axios.get('/user?ID=12345') .then( ...

  7. Authorize的Forms认证

    页面请求步骤: 1.登录地址: http://localhost:4441/SysLogin/AdminLogin 2.登陆成功地址:http://localhost:4441/Frame/MainF ...

  8. 树莓派 Raspberry Pi 更换国内源

    http://www.shumeipaiba.com/wanpai/jiaocheng/16.html

  9. [Beta]M2事后分析

    计划 你原计划的工作是否最后都做完了? 如果有没做完的,为什么? 答:没有,全部的功能没有实现.其中,界面还差两个,逻辑还差闹钟逻辑和群组逻辑,可以说这些东西是我们的核心功能之一,缺失了他们对我们整个 ...

  10. 《Linux内核设计与实现》第17章学习笔记

    第17章.设备与模块 17.1设备类型 1.块设备(blkdev): 寻址以块为单位,通常支持重定位操作.通过称为“块设备节点”的特殊文件来访问. 2.字符设备(cdev): 不可寻址,仅提供数据的流 ...