【题目大意】

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
 
【思路】
这道题迷之好写,因为思路条理太清晰了!
我们每个点就是一棵线段树,维护它到根的每个数字的个数,但是这样会MLE所以自然而然地用主席树来维护。
u->v路径上每种的个数就等于sum[u]-sum[lca(u,v)]+sum[v]-sum[fa[lca(u,v)]]。
写起来特别爽。
然而我RE了一个上午。接着突然发现题意“(u,v)表示u到v有一条边)它居然是无向的??天真地以为有向u->v,调出了一开始的程序,默默地改掉,默默地AC...
还我两小时的人生!!!!
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<vector>
  6. #define lson l,m
  7. #define rson m+1,r
  8. using namespace std;
  9. const int MAXN=+;
  10. const int DEG=;
  11. int w[MAXN];
  12. vector<int> E[MAXN];
  13. int d,hash[MAXN];
  14. int T[MAXN],tot,sum[MAXN<<],L[MAXN<<],R[MAXN<<];
  15. int anc[MAXN][DEG],dep[MAXN];
  16. int n,m;
  17.  
  18. /*Chairman Tree*/
  19. int build(int l,int r)
  20. {
  21. int rt=++tot;
  22. sum[rt]=;
  23. if (l!=r)
  24. {
  25. int m=(l+r)>>;
  26. L[rt]=build(lson);
  27. R[rt]=build(rson);
  28. }
  29. return rt;
  30. }
  31.  
  32. int update(int pre,int l,int r,int x)
  33. {
  34. int rt=++tot;
  35. L[rt]=L[pre],R[rt]=R[pre];
  36. sum[rt]=sum[pre]+;
  37. if (l!=r)
  38. {
  39. int m=(l+r)>>;
  40. if (x<=m) L[rt]=update(L[pre],lson,x);
  41. else R[rt]=update(R[pre],rson,x);
  42. }
  43. return rt;
  44. }
  45.  
  46. int query(int u,int v,int lca,int lcafa,int l,int r,int k)
  47. {
  48. if (l==r) return l;
  49. int num=(sum[L[u]]-sum[L[lca]]+sum[L[v]]-sum[L[lcafa]]);
  50. int m=(l+r)>>;
  51. if (num>=k) return query(L[u],L[v],L[lca],L[lcafa],lson,k);
  52. else return query(R[u],R[v],R[lca],R[lcafa],rson,k-num);
  53. }
  54.  
  55. /*LCA*/
  56. void getanc()
  57. {
  58. for (int i=;i<DEG;i++)
  59. for (int j=;j<=n;j++)
  60. anc[j][i]=anc[anc[j][i-]][i-];
  61. }
  62.  
  63. int swim(int x,int H)
  64. {
  65. for (int i=;H>;i++)
  66. {
  67. if (H&) x=anc[x][i];
  68. H>>=;
  69. }
  70. return x;
  71. }
  72.  
  73. int LCA(int u,int v)
  74. {
  75. if (dep[u]<dep[v]) swap(u,v);
  76. u=swim(u,dep[u]-dep[v]);
  77. if (u==v) return u;
  78. for (int i=DEG-;i>=;i--)
  79. {
  80. if (anc[u][i]!=anc[v][i])
  81. {
  82. u=anc[u][i];
  83. v=anc[v][i];
  84. }
  85. }
  86. return anc[u][];
  87. }
  88.  
  89. /*main*/
  90. void dfs(int u,int pa,int depth)
  91. {
  92. anc[u][]=pa;
  93. dep[u]=depth;
  94. int x=lower_bound(hash+,hash+d+,w[u])-hash;
  95. T[u]=update(T[pa],,d,x);
  96. for (int i=;i<E[u].size();i++)
  97. if (E[u][i]!=pa) dfs(E[u][i],u,depth+);
  98. }
  99.  
  100. void init()
  101. {
  102. scanf("%d%d",&n,&m);
  103. for (int i=;i<=n;i++) scanf("%d",&w[i]),hash[i]=w[i];
  104. sort(hash+,hash+n+);
  105. d=unique(hash+,hash+n+)-(hash+);
  106.  
  107. for (int i=;i<n;i++)
  108. {
  109. int u,v;
  110. scanf("%d%d",&u,&v);
  111. E[u].push_back(v);
  112. E[v].push_back(u);
  113. }
  114.  
  115. tot=;
  116. T[]=build(,d);//对于根先建立主席树
  117. }
  118.  
  119. void solve()
  120. {
  121. getanc();
  122. int preans=;
  123. for (int i=;i<m;i++)
  124. {
  125. int u,v,k;
  126. scanf("%d%d%d",&u,&v,&k);
  127. u=u^preans;
  128. int lca=LCA(u,v);
  129. int ans=query(T[u],T[v],T[lca],T[anc[lca][]],,d,k);
  130. printf("%d",hash[ans]);
  131. if (i!=m-) printf("\n");
  132. preans=hash[ans];
  133. }
  134. }
  135.  
  136. int main()
  137. {
  138. init();
  139. dfs(,,);
  140. solve();
  141. return ;
  142. }

【树上主席树】BZOJ2588-Count on a tree的更多相关文章

  1. 洛谷P2633/bzoj2588 Count on a tree (主席树)

    洛谷P2633/bzoj2588 Count on a tree 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K ...

  2. Count on a tree 树上主席树

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

  3. 【洛谷2633】Count on a tree(树上主席树)

    点此看题面 大致题意: 给你一棵树,每次问你两点之间第\(k\)小的点权,强制在线. 主席树 这种题目强制在线一般就是数据结构了. 而看到区间第\(k\)小,很容易就能想到主席树. 至少不会有人想到树 ...

  4. [bzoj2588][count on a tree] (主席树+lca)

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

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

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

  6. p3302 [SDOI2013]森林(树上主席树+启发式合并)

    对着题目yy了一天加上看了一中午题解,终于搞明白了我太弱了 连边就是合并线段树,把小的集合合并到大的上,可以保证规模至少增加一半,复杂度可以是\(O(logn)\) 合并的时候暴力dfs修改倍增数组和 ...

  7. [CSP-S模拟测试]:e(树上主席树)

    题目传送门(内部题66) 输入格式 第一行,一个正整数$n$,一个自然数$q$,一个整数$type$.第二行,$n$个正整数,代表$a_i$.接下来$n-1$行,每行两个正整数$u$.$v$,代表树中 ...

  8. bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...

  9. BZOJ2588 Count on a tree 【树上主席树】

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB Submit: 7577  Solved: 185 ...

随机推荐

  1. jquery实现简单轮播

    先上简单的html代码 <!DOCTYPE HTML> <html> <head> <link rel="stylesheet" type ...

  2. VC连接access

    (1)首先拷贝 c:\program files\common files\system\ado\ 目录中的 msado15.dll 文件到项目中. (2)在VC中加入DLL,具体方法如下: (3)创 ...

  3. linux网络配置完全解析

    概述:熟悉了windows下面的网络配置,对linux下的网络配置缺未必了解透彻.熟练掌握linux下的网络配置原理,能帮助我们更容易掌握网络传输原理:同时具备一些网络连接不通对应问题的排查能力.文本 ...

  4. linux驱动开发:用户空间操作LCD显示简单的图片【转】

    转自:http://blog.csdn.net/changliang7731/article/details/53074616 上一章我们简单介绍了LCD的一些基本原理.当然更深奥的还有,比如gamm ...

  5. juery给所有ID属性相同的div绑定一个事件

    案例: <div id="div1">内容</div> <div id="div1">内容</div> < ...

  6. jekyll安装及使用

    清除旧版Ruby,若存在 yum remove ruby 若为源码,使用如下命令 cd <your-ruby-source-path> make uninstall 下面开始安装Ruby ...

  7. email的传输协议与格式(资源链接)

    以下链接为转载. 传输协议: 发:SMTP 收:POP3, IMAP 格式: MIME

  8. [转]Java中堆和栈创建对象的区别

    转载自http://blog.csdn.net/hbhhww/article/details/8152838 栈与堆都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序 ...

  9. 关于IPMI的几个问题

    https://blog.csdn.net/lanyang123456/article/details/51712878

  10. 关于HTML5 boilerplate 的一些笔记

    最近在研究HTML5 boilerplate的模版,以此为线索可以有条理地学习一些前端的best practice,好过在W3C的文档汪洋里大海捞针……啊哈哈哈…… 开头的IE探测与no-js类是什么 ...