题意:

求树上A,B两点路径上第K小的数

分析:

同样是可持久化线段树,只是这一次我们用它来维护树上的信息。

我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上。

比如说我们从一棵树的根节点进行DFS,得到根节点到各节点的距离dist[x]——这是一个根-x路径上点与根节点距离的前缀和。

利用这个前缀和,我们可以解决一些树上任意路径的问题,比如在线询问[a,b]点对的距离——答案自然是dist[a]+dist[b]-2*dist[lca(a,b)]。

同理,我们可以利用可持久化线段树来解决树上任意路径的问题。

DFS遍历整棵树,然后在每个节点上建立一棵线段树,某一棵线段树的“前一版本”是位于该节点父亲节点fa的线段树。

利用与之前类似的方法插入点权(排序离散)。那么对于询问[a,b],答案就是root[a]+root[b]-root[lca(a,b)]-root[fa[lca(a,b)]]上的第k大。

  1. // File Name: cot.cpp
  2. // Author: Zlbing
  3. // Created Time: 2013年10月09日 星期三 19时24分55秒
  4.  
  5. #include<iostream>
  6. #include<string>
  7. #include<algorithm>
  8. #include<cstdlib>
  9. #include<cstdio>
  10. #include<set>
  11. #include<map>
  12. #include<vector>
  13. #include<cstring>
  14. #include<stack>
  15. #include<cmath>
  16. #include<queue>
  17. using namespace std;
  18. #define CL(x,v); memset(x,v,sizeof(x));
  19. #define INF 0x3f3f3f3f
  20. #define LL long long
  21. #define REP(i,r,n) for(int i=r;i<=n;i++)
  22. #define RREP(i,n,r) for(int i=n;i>=r;i--)
  23. const int MAXN=1e5+;
  24. const int POW=;
  25. int num[MAXN],hash[MAXN];
  26. int ls[MAXN*],rs[MAXN*];
  27. int sum[MAXN*];
  28. int root[MAXN];
  29. vector<int> G[MAXN];
  30. int d[MAXN];
  31. int p[MAXN][POW];
  32. int tot;
  33. int f[MAXN];
  34. void build(int l,int r,int& rt)
  35. {
  36. rt=++tot;
  37. sum[rt]=;
  38. if(l>=r)return;
  39. int m=(l+r)>>;
  40. build(l,m,ls[rt]);
  41. build(m+,r,rs[rt]);
  42. }
  43. void update(int last,int p,int l,int r,int &rt)
  44. {
  45. rt=++tot;
  46. ls[rt]=ls[last];
  47. rs[rt]=rs[last];
  48. sum[rt]=sum[last]+;
  49. if(l>=r)return ;
  50. int m=(l+r)>>;
  51. if(p<=m)update(ls[last],p,l,m,ls[rt]);
  52. else update(rs[last],p,m+,r,rs[rt]);
  53. }
  54. int query(int left_rt,int right_rt,int lca_rt,int lca_frt,int l,int r,int k)
  55. {
  56. if(l>=r)return l;
  57. int m=(l+r)>>;
  58. int cnt=sum[ls[right_rt]]+sum[ls[left_rt]]-sum[ls[lca_rt]]-sum[ls[lca_frt]];
  59. if(k<=cnt)
  60. return query(ls[left_rt],ls[right_rt],ls[lca_rt],ls[lca_frt],l,m,k);
  61. else
  62. return query(rs[left_rt],rs[right_rt],rs[lca_rt],rs[lca_frt],m+,r,k-cnt);
  63. }
  64. void dfs(int u,int fa,int cnt)
  65. {
  66. f[u]=fa;
  67. d[u]=d[fa]+;
  68. p[u][]=fa;
  69. for(int i=;i<POW;i++)p[u][i]=p[p[u][i-]][i-];
  70.  
  71. update(root[fa],num[u],,cnt,root[u]);
  72. for(int i=;i<(int)G[u].size();i++)
  73. {
  74. int v=G[u][i];
  75. if(v==fa)continue;
  76. dfs(v,u,cnt);
  77. }
  78. }
  79. int lca(int a,int b)
  80. {
  81. if(d[a]>d[b])a^=b,b^=a,a^=b;
  82. if(d[a]<d[b])
  83. {
  84. int del=d[b]-d[a];
  85. for(int i=;i<POW;i++)
  86. if(del&(<<i))b=p[b][i];
  87. }
  88. if(a!=b)
  89. {
  90. for(int i=POW-;i>=;i--)
  91. {
  92. if(p[a][i]!=p[b][i])
  93. {
  94. a=p[a][i],b=p[b][i];
  95. }
  96. }
  97. a=p[a][],b=p[b][];
  98. }
  99. return a;
  100. }
  101. int main()
  102. {
  103. int n,m;
  104. while(~scanf("%d%d",&n,&m))
  105. {
  106. REP(i,,n)
  107. {
  108. G[i].clear();
  109. }
  110. CL(d,);
  111. CL(p,);
  112. CL(f,);
  113. REP(i,,n)
  114. {
  115. scanf("%d",&num[i]);
  116. hash[i]=num[i];
  117. }
  118. tot=;
  119. sort(hash+,hash++n);
  120. int cnt=unique(hash+,hash+n+)-hash-;
  121. REP(i,,n)
  122. {
  123. num[i]=lower_bound(hash+,hash+cnt+,num[i])-hash;
  124. }
  125. int a,b,c;
  126. REP(i,,n-)
  127. {
  128. scanf("%d%d",&a,&b);
  129. G[a].push_back(b);
  130. G[b].push_back(a);
  131. }
  132. build(,cnt,root[]);
  133. dfs(,,cnt);
  134. REP(i,,m)
  135. {
  136. scanf("%d%d%d",&a,&b,&c);
  137. int t=lca(a,b);
  138. int id=query(root[a],root[b],root[t],root[f[t]],,cnt,c);
  139. printf("%d\n",hash[id]);
  140. }
  141. }
  142. return ;
  143. }

SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)的更多相关文章

  1. Count on a tree(树上路径第K小)

    题目链接:https://www.spoj.com/problems/COT/en/ 题意:求树上A,B两点路径上第K小的数 思路:主席树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上. ...

  2. spoj COT - Count on a tree (树上第K小 LCA+主席树)

    链接: https://www.spoj.com/problems/COT/en/ 思路: 首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们 ...

  3. Count on a tree 树上区间第K小

    Count on a tree 题意:求路径 u到v上的 第k小的权重. 题解:先DFS建数, 然后对于每个节点往上跑出一颗主席树, 然后每次更新. 查询的时候, u, v, k, 找到  z = l ...

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

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

  5. 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  ...

  6. SPOJ 10628 Count on a tree(Tarjan离线 | RMQ-ST在线求LCA+主席树求树上第K小)

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

  7. 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 ...

  8. 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 ...

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

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

随机推荐

  1. SharePoint Attachement操作代码

    下载文件 如果下载其它类别的文件:  SPSecurity.RunWithElevatedPrivileges(].ToString();                            swi ...

  2. jquery自调用匿名函数解析

    alert("undefined" in window);        (function (window, undefined) {            //构造jQuery ...

  3. 27、Jquery 事件

    Jquery 事件 在javascript中事件调用方式为onclick.onmouseover等,在jquery中 使用事件无需写前面的on bind()方法 为元素绑定事件 $("#id ...

  4. final----这篇文章是我收获很大

    final 用于声明属性.方法和类,分别表示属性不可变,方法不可重写,类不可继承. [转]Java final 修饰符知识点总结 final从字面上理解含义为“最后的,最终的”.在Java中也同样表示 ...

  5. google code 上传源码

    在使用google code 的时候 做个备份, git clone https://wushuangzilong@code.google.com/p/maplebanana-proxy/ git c ...

  6. Object-C 类实现

    这篇为Object-C添加方法的后续. 这里我们应该在类的实现(.m)文件中写 #import "Photo.h" @implementation Photo - (NSStrin ...

  7. iOS程序员的自我修养之道

    新技术的了解渠道 WWDC开发者大会视频 官方文档 General -> Guides -> iOS x.x API Diffs 程序员的学习 iOS技术的学习 官当文档 Sample C ...

  8. window远程连接linux

    一.字符界面连接Linux    1.直接使用window自带的telnet. 2.但现在Linux一般都不启用telnet,而是启用ssh.这样的话,window就要安装客户端来访问Linux了.这 ...

  9. COM简单应用示例

    使用com技术开发模式进行的示例. com技术关键部分源码:主要将所有接口都写入到这个文件中 testinterface.h #ifndef TESTINTERFACE_H #define TESTI ...

  10. WF学习笔记(二)

    -DoWhile循环:当[Condition]条件为真时会执行[Body]中的内容, 当[Condition]条件为假时会执行[Body]中的内容一次 -ForEach<T> 循环 :[V ...