COT2 - Count on a tree II

You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.

We will ask you to perform the following operation:

u v : ask for how many different integers that represent the weight of nodes there are on the path from u to v.


Input

In the first line there are two integers N and M. (N <= 40000, M <= 100000)

In the second line there are N integers. The i-th integer denotes the weight of the i-th node.

In the next N-1 lines, each line contains two integers u v, which describes an edge (u, v).

In the next M lines, each line contains two integers u v, which means an operation asking for how many different integers that represent the weight of nodes there are on the path from u to v.


Output

For each operation, print its result.


Example

Input:

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

Output:

  1. 4
  2. 4

思路:树上莫队的模板题

LCA用tarjan算法来找,可以变成DFS以后的序列,然后再用莫队算法的思路。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int const SIZE=40100;
  4. int const BLOCK_SIZE=300;
  5. //利用hash记录LCA
  6. struct Hash{
  7. typedef struct __t{int a;int b;__t(int aa=0,int bb=0):a(aa),b(bb){}}key_t;
  8. typedef int value_t;
  9. enum{MOD=0x1fffff};
  10. key_t keys[MOD+1];
  11. value_t values[MOD+1];
  12. int head[MOD+1];
  13. int next[MOD+1];
  14. int toUsed;
  15. Hash():toUsed(0){fill(head,head+MOD+1,-1);}
  16. void clear(){fill(head,head+MOD+1,-1);toUsed=0;}
  17. int getKey(key_t const&key)const {
  18. int ret=17;
  19. ret=ret*37+key.a;
  20. ret=ret*37+key.b;
  21. return ret;
  22. }
  23. void insert(key_t const&key,value_t const&value){
  24. int k = getKey(key) & MOD;
  25. keys[toUsed] = key;
  26. values[toUsed] = value;
  27. next[toUsed] = head[k];
  28. head[k] = toUsed++;
  29. }
  30. value_t find(key_t const&key)const{
  31. int k = getKey(key) & MOD;
  32. for(int i=head[k];i!=-1;i=next[i]){
  33. if ( keys[i].a == key.a && keys[i].b == key.b ) return values[i];
  34. }
  35. return 0;
  36. }
  37. void disp(FILE*fp)const{
  38. for(int i=1;i<toUsed;++i){
  39. fprintf(fp,"(%d %d): %d\n",keys[i].a,keys[i].b,values[i]);
  40. }
  41. }
  42. }Lca;
  43. struct dege_t{
  44. int to;
  45. int next;
  46. }Edge[SIZE<<1];
  47. int ECnt=1;
  48. int Vertex[SIZE]={0};
  49. inline void makeEdge(int a,int b)
  50. {
  51. Edge[ECnt].to=b;
  52. Edge[ECnt].next=Vertex[a];
  53. Vertex[a]=ECnt++;
  54. Edge[ECnt].to=a;
  55. Edge[ECnt].next=Vertex[b];
  56. Vertex[b]=ECnt++;
  57. }
  58. //生成DFS序
  59. int InIdx[SIZE],OutIdx[SIZE];
  60. int NewIdx[SIZE<<1];
  61. int NCnt = 1;
  62. void dfs(int node,int parent){
  63. NewIdx[NCnt] = node;
  64. InIdx[node] = NCnt++;
  65. for(int next=Vertex[node];next;next=Edge[next].next){
  66. int to = Edge[next].to;
  67. if ( to != parent ) dfs(to,node);
  68. }
  69. NewIdx[NCnt] = node;
  70. OutIdx[node] = NCnt++;
  71. }
  72. //Tarjan算法中用到的并查集
  73. int Father[SIZE];
  74. int find(int x){return x==Father[x]?x:Father[x]=find(Father[x]);}
  75. bool Flag[SIZE] = {false};
  76. vector<vector<int> > Questions(SIZE,vector<int>());
  77. //Tarjan算法一次性求出所有的LCA
  78. void Tarjan(int u,int parent){
  79. Father[u] = u;
  80. Flag[u] = true;
  81. for(int next=Vertex[u];next;next=Edge[next].next){
  82. int to = Edge[next].to;
  83. if ( to == parent ) continue;
  84. Tarjan(to,u);
  85. Father[to] = u;
  86. }
  87. vector<int>&vec=Questions[u];
  88. for(vector<int>::iterator it=vec.begin();it!=vec.end();++it){
  89. int v = *it;
  90. if ( Flag[v] ){
  91. int r = find(v);
  92. Lca.insert(Hash::key_t(u,v),r);
  93. Lca.insert(Hash::key_t(v,u),r);
  94. }
  95. }
  96. }
  97. struct _t{
  98. int s,e;
  99. int idx;
  100. int lca;
  101. };
  102. bool operator < (_t const&lhs,_t const&rhs){
  103. int ln = lhs.s / BLOCK_SIZE;
  104. int rn = rhs.s / BLOCK_SIZE;
  105. return ln < rn || ( ln == rn && lhs.e < rhs.e );
  106. }
  107. int N,M;
  108. int A[SIZE];
  109. _t B[100000];
  110. //将原树上的路径问题转化为DFS序中的区间问题
  111. inline void mkQuestion(int a,int b,int idx){
  112. int lca = Lca.find(Hash::key_t(a,b));
  113. if ( lca == a || lca == b ){
  114. int t = lca == a ? b : a;
  115. B[idx].s = OutIdx[t];
  116. B[idx].e = OutIdx[lca];
  117. B[idx].lca = 0;
  118. }else{
  119. B[idx].lca = lca;
  120. if ( OutIdx[a] < InIdx[b] ) B[idx].s = OutIdx[a], B[idx].e = InIdx[b];
  121. else B[idx].s = OutIdx[b], B[idx].e = InIdx[a];
  122. }
  123. }
  124. int MoAns;
  125. int Ans[100000],Cnt[SIZE];
  126. inline void insert(int n){
  127. if ( 1 == ++Cnt[n] ) ++MoAns;
  128. }
  129. inline void remove(int n){
  130. if ( 0 == --Cnt[n] ) --MoAns;
  131. }
  132. void MoOp(int idx){
  133. int k = NewIdx[idx];
  134. if ( Flag[k] ) remove(A[k]);
  135. else insert(A[k]);
  136. Flag[k] ^= 1;
  137. }
  138. void Mo(){
  139. sort(B,B+M);
  140. fill(Flag,Flag+N+1,false);
  141. int curLeft = 1;
  142. int curRight = 0;
  143. MoAns = 0;
  144. for(int i=0;i<M;++i){
  145. while( curRight < B[i].e ) MoOp(++curRight);
  146. while( curLeft > B[i].s ) MoOp(--curLeft);
  147. while( curRight > B[i].e ) MoOp(curRight--);
  148. while( curLeft < B[i].s ) MoOp(curLeft++);
  149. if ( B[i].lca ){
  150. Ans[B[i].idx] = MoAns + ( 0 == Cnt[A[B[i].lca]] ? 1 : 0 );
  151. }else{
  152. Ans[B[i].idx] = MoAns;
  153. }
  154. }
  155. }
  156. void init(int n){
  157. ECnt = NCnt = 1;
  158. fill(Vertex,Vertex+n+1,0);
  159. fill(Flag,Flag+n+1,false);
  160. }
  161. int getUnsigned(){
  162. char ch = getchar();
  163. while( ch > '9' || ch < '0' ) ch = getchar();
  164. int ret = 0;
  165. do ret = ret * 10 + (int)(ch-'0');while( '0' <= (ch=getchar()) && ch <= '9' );
  166. return ret;
  167. }
  168. int W[SIZE];
  169. bool read(){
  170. if ( EOF == scanf("%d",&N) ) return false;
  171. M = getUnsigned();
  172. init(N);
  173. //权值输入并离散化
  174. for(int i=1;i<=N;++i) W[i] = A[i] = getUnsigned();
  175. sort(W+1,W+N+1);
  176. int* pn = unique(W+1,W+N+1);
  177. for(int i=1;i<=N;++i) A[i] = lower_bound(W+1,pn,A[i]) - W;
  178. int a,b;
  179. for(int i=1;i<N;++i){
  180. a = getUnsigned();
  181. b = getUnsigned();
  182. makeEdge(a,b);
  183. }
  184. dfs(1,0);
  185. for(int i=0;i<M;++i){
  186. B[i].s = getUnsigned();
  187. B[i].e = getUnsigned();
  188. B[i].idx = i;
  189. Questions[B[i].s].push_back(B[i].e);
  190. Questions[B[i].e].push_back(B[i].s);
  191. }
  192. Tarjan(1,0);
  193. for(int i=0;i<M;++i) mkQuestion(B[i].s,B[i].e,i);
  194. return true;
  195. }
  196. int main(){
  197. //freopen("1.txt","r",stdin);
  198. while ( read() ){
  199. Mo();
  200. for(int i=0;i<M;++i)printf("%d\n",Ans[i]);
  201. }
  202. return 0;
  203. }

COT2 - Count on a tree II(树上莫队)的更多相关文章

  1. spoj COT2 - Count on a tree II 树上莫队

    题目链接 http://codeforces.com/blog/entry/43230树上莫队从这里学的,  受益匪浅.. #include <iostream> #include < ...

  2. SP10707 COT2 - Count on a tree II (树上莫队)

    大概学了下树上莫队, 其实就是在欧拉序上跑莫队, 特判lca即可. #include <iostream> #include <algorithm> #include < ...

  3. SP10707 COT2 - Count on a tree II [树上莫队学习笔记]

    树上莫队就是把莫队搬到树上-利用欧拉序乱搞.. 子树自然是普通莫队轻松解决了 链上的话 只能用树上莫队了吧.. 考虑多种情况 [X=LCA(X,Y)] [Y=LCA(X,Y)] else void d ...

  4. SPOJ COT2 Count on a tree II 树上莫队算法

    题意: 给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问. 每次询问路径\(u \to v\)上有多少个权值不 ...

  5. [SPOJ]Count on a tree II(树上莫队)

    树上莫队模板题. 使用欧拉序将树上路径转化为普通区间. 之后莫队维护即可.不要忘记特判LCA #include<iostream> #include<cstdio> #incl ...

  6. SPOJ COT2 - Count on a tree II(LCA+离散化+树上莫队)

    COT2 - Count on a tree II #tree You are given a tree with N nodes. The tree nodes are numbered from  ...

  7. spoj COT2 - Count on a tree II

    COT2 - Count on a tree II http://www.spoj.com/problems/COT2/ #tree You are given a tree with N nodes ...

  8. 【SPOJ10707】 COT2 Count on a tree II

    SPOJ10707 COT2 Count on a tree II Solution 我会强制在线版本! Solution戳这里 代码实现 #include<stdio.h> #inclu ...

  9. SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

    题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无 ...

随机推荐

  1. JAVA原始的导出excel文件,快捷通用 方便 还能够导出word文档哦

    如今导出excel基本上都是用poi了,当报表格式非常负责的时候 开发难度会加大 假设报表有格式有变化 那就更复杂了,先发现一个非常老的技术.能够解决格式复杂的报表. 实例代码例如以下: <%@ ...

  2. Meteor第一个应用程序

    这一个小教程将教你如何建立你的第一个 Meteor 应用程序. 步骤 1 - 创建App 要创建应用程序,我们将从命令提示符窗口运行 meteor create 命令.该应用程序的名称是 meteor ...

  3. WEKA简单介绍与资源汇总

    简单介绍 Weka是一个开源的数据挖掘软件,里面集成了很多经典的机器学习算法,在高校和科研机构中受到了广泛的应用. 具体的简单介绍和简单的使用请參考文档:<使用Weka进行数据挖掘>. 学 ...

  4. Apach POI 如何拿到有公式的单元格,计算结果

    public static void getFormulaCellValue(){ FileInputStream fis = new FileInputStream("c:/temp/te ...

  5. 动态标绘演示系统1.4.3(for ArcGIS Flex)

    标绘有API文档啦! 在线浏览 ------------------------------------------------------------------------------------ ...

  6. NS3网络仿真(12): ICMPv4协议

    快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 ICMP的全称是 Internet ControlMessage Protocol . 其目的就是 ...

  7. css3最新版中文参考手册在线浏览

    对于CSS 3.0,它对于我们Web设计人员来说不只是新奇的技术,更重要的是这些全新概念的Web应用给我们的设计开发提高了效率以及更多的无限可能性,我们将不必再依赖图片或者 Javascript 去完 ...

  8. Highcharts报表——让你的网页上图表画的飞起

    Highcharts是一款纯javascript编写的图表库,能够很简单便捷的在Web网站或Web应用中添加交互性的图表,Highcharts目前支持直线图.曲线图.面积图.柱状图.饼图.散点图等多达 ...

  9. Xcode The identity used to sign the executable is no longer valid. 错误解决

    Xcode真机调试时出现问题:Xcode The identity used to sign the executable is no longer valid. Please verify that ...

  10. Eclipse添加Qt插件

    此文件仅为步骤操作作一个记录,以便以后方便查阅. 1.操作大体参考这个网站:http://blog.csdn.net/defonds/article/details/5013412 2.我的运行环境: ...