题目描述

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

输入

第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。

输出

M行,表示每个询问的答案。最后一个询问不输出换行符

样例输入

8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2

样例输出

2
8
9
105
7

提示

HINT:
N,M<=100000
 
  
  查询一个路径上第k小,就相当于查询序列上区间第k小,可以想到用主席树维护。但这道题是在树上完成的操作,所以并不能像平常主席树一样只用r时刻减掉l-1时刻的线段树查询。对于树上的路径(以x和y之间的路径为例),可以把它分成两部分:x到lca和y到lca。这样整条路径上的信息就可以通过这两条链相加得到。所以直接用x时刻线段树+y时刻线段树-lca时刻线段树-lca的父节点时刻线段树就得到路径上状态。每个时刻线段树由它的父节点时刻线段树转移过来。
最后附上代码。
  1. #include<map>
  2. #include<set>
  3. #include<queue>
  4. #include<cmath>
  5. #include<cstdio>
  6. #include<cstring>
  7. #include<iostream>
  8. #include<algorithm>
  9. #define mid (L+R)/2
  10. using namespace std;
  11. int ans;
  12. int tot;
  13. int cnt;
  14. int anc;
  15. int n,m,q;
  16. int x,y,z;
  17. int d[100010];
  18. int v[100010];
  19. int h[100010];
  20. int l[3000010];
  21. int r[3000010];
  22. int to[200010];
  23. int head[100010];
  24. int next[200010];
  25. int sum[3000010];
  26. int root[100010];
  27. int f[100010][20];
  28. map<int,int>b;
  29. void add(int x,int y)
  30. {
  31. tot++;
  32. next[tot]=head[x];
  33. head[x]=tot;
  34. to[tot]=y;
  35. }
  36. int lca(int x,int y)
  37. {
  38. if(d[x]<d[y])
  39. {
  40. swap(x,y);
  41. }
  42. int dep=d[x]-d[y];
  43. for(int i=0;i<=19;i++)
  44. {
  45. if((dep&(1<<i))!=0)
  46. {
  47. x=f[x][i];
  48. }
  49. }
  50. if(x==y)
  51. {
  52. return x;
  53. }
  54. for(int i=19;i>=0;i--)
  55. {
  56. if(f[x][i]!=f[y][i])
  57. {
  58. x=f[x][i];
  59. y=f[y][i];
  60. }
  61. }
  62. return f[x][0];
  63. }
  64. int updata(int pre,int L,int R,int k)
  65. {
  66. int rt=++cnt;
  67. l[rt]=l[pre];
  68. r[rt]=r[pre];
  69. sum[rt]=sum[pre]+1;
  70. if(L==R)
  71. {
  72. return rt;
  73. }
  74. else
  75. {
  76. if(k<=mid)
  77. {
  78. l[rt]=updata(l[pre],L,mid,k);
  79. }
  80. else
  81. {
  82. r[rt]=updata(r[pre],mid+1,R,k);
  83. }
  84. }
  85. return rt;
  86. }
  87. int query(int x,int y,int anc,int fa,int L,int R,int k)
  88. {
  89. if(L==R)
  90. {
  91. return b[L];
  92. }
  93. int num=sum[l[x]]+sum[l[y]]-sum[l[anc]]-sum[l[fa]];
  94. if(num>=k)
  95. {
  96. return query(l[x],l[y],l[anc],l[fa],L,mid,k);
  97. }
  98. else
  99. {
  100. return query(r[x],r[y],r[anc],r[fa],mid+1,R,k-num);
  101. }
  102. }
  103. void dfs(int x,int fa)
  104. {
  105. d[x]=d[fa]+1;
  106. int k=lower_bound(h+1,h+1+m,v[x])-h;
  107. b[k]=v[x];
  108. root[x]=updata(root[fa],1,n,k);
  109. for(int i=1;i<=19;i++)
  110. {
  111. f[x][i]=f[f[x][i-1]][i-1];
  112. }
  113. for(int i=head[x];i;i=next[i])
  114. {
  115. if(to[i]!=fa)
  116. {
  117. f[to[i]][0]=x;
  118. dfs(to[i],x);
  119. }
  120. }
  121. }
  122. int main()
  123. {
  124. scanf("%d%d",&n,&q);
  125. for(int i=1;i<=n;i++)
  126. {
  127. scanf("%d",&v[i]);
  128. h[i]=v[i];
  129. }
  130. sort(h+1,h+1+n);
  131. m=unique(h+1,h+1+n)-h-1;
  132. for(int i=1;i<n;i++)
  133. {
  134. scanf("%d%d",&x,&y);
  135. add(x,y);
  136. add(y,x);
  137. }
  138. dfs(1,0);
  139. for(int i=1;i<=q;i++)
  140. {
  141. scanf("%d%d%d",&x,&y,&z);
  142. x=x^ans;
  143. anc=lca(x,y);
  144. ans=query(root[x],root[y],root[anc],root[f[anc][0]],1,n,z);
  145. printf("%d\n",ans);
  146. }
  147. }

BZOJ2588Count on a tree——LCA+主席树的更多相关文章

  1. [BZOJ2588]Count on a tree(LCA+主席树)

    题面 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问 ...

  2. 【bzoj2588/P2633】count on a tree —— LCA + 主席树

    (以下是luogu题面) 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问 ...

  3. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  4. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  5. LCA+主席树 (求树上路径点权第k大)

      SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given ...

  6. Count on a tree 树上主席树

    Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...

  7. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  8. BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序

    BZOJ_1803_Spoj1487 Query on a tree III_主席树 Description You are given a node-labeled rooted tree with ...

  9. 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

随机推荐

  1. 1-微信小程序开发(安装软件和运行第一个微信小程序)

    https://developers.weixin.qq.com/miniprogram/dev/ 我的 打开 上传成功后

  2. golang 常用包安装

    常用到的: go get -v github.com/nsf/gocode go get -v github.com/rogpeppe/godef go get -v golang.org/x/too ...

  3. http一次请求过程

    物理层:支持底层网络协议: 其中网络层支持IP协议: 传输层支持TCP协议,它是面向连接的: 应用层支持 http,ftp  tftp,SMTP,DHCP协议 一个完整的http请求过程: 1.浏览器 ...

  4. UVA1626 - Brackets sequence(区间DP--括号匹配+递归打印)

    题目描写叙述: 定义合法的括号序列例如以下: 1 空序列是一个合法的序列 2 假设S是合法的序列.则(S)和[S]也是合法的序列 3 假设A和B是合法的序列.则AB也是合法的序列 比如:以下的都是合法 ...

  5. 在SpringMVC中使用HandlerInterceptor来实现拦截器功能

    需求:我们需要在请求某些特定的URL(URL格式为Restful格式)时添加拦截器,以实现进行权限控制. 如:/ResourcePlan/projectCode/P1503127828/PROJECT ...

  6. Roslyn入门(一)-C#语法分析

    演示环境 Visual Studio 2017 .NET Compiler Platform SDK 简介 今天,Visual Basic和C#编译器是黑盒子:输入文本然后输出字节,编译管道的中间阶段 ...

  7. Spring RPC 入门学习(2)-获取Map对象

    Spring RPC传递Map用例编写 1. 新建RPC接口类 package com.cvicse.ump.rpc.interfaceDefine; import java.util.Map; pu ...

  8. M1/M2 总结

    时光是一列不会回头的列车. 这一学期这么快就过去了,当时刚开始软件工程的那些日子还历历在目.不知道那些如风般过去的日子带给我了什么.然而我又清楚地认识到自己已经改变了. 刚开始软件工程的时候,我对团队 ...

  9. 第三个Sprint冲刺第3天

    成员:罗凯旋.罗林杰.吴伟锋.黎文衷 组内各成员加紧完成自己的工作.

  10. PyXB: Python XML Schema Bindings

    http://pyxb.sourceforge.net/ PyXB (“pixbee”) is a pure Python package that generates Python source c ...