题目链接:http://www.spoj.com/problems/COT2/

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 perfrom 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 ith integer denotes the weight of the ith 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.

题目大意:给一棵树,每个点有一个权值。多次询问路径(a, b)上有多少个权值不同的点。

思路:参考VFK WC 2013 糖果公园 park 题解(此题比COT2要难。)

http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

代码(2.37S):

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. const int MAXV = ;
  5. const int MAXE = MAXV << ;
  6. const int MAXQ = ;
  7. const int MLOG = ;
  8.  
  9. namespace Bilibili {
  10.  
  11. int head[MAXV], val[MAXV], ecnt;
  12. int to[MAXE], next[MAXE];
  13. int n, m;
  14.  
  15. int stk[MAXV], top;
  16. int block[MAXV], bcnt, bsize;
  17.  
  18. struct Query {
  19. int u, v, id;
  20. void read(int i) {
  21. id = i;
  22. scanf("%d%d", &u, &v);
  23. }
  24. void adjust() {
  25. if(block[u] > block[v]) swap(u, v);
  26. }
  27. bool operator < (const Query &rhs) const {
  28. if(block[u] != block[rhs.u]) return block[u] < block[rhs.u];
  29. return block[v] < block[rhs.v];
  30. }
  31. } ask[MAXQ];
  32. int ans[MAXQ];
  33. /// Graph
  34. void init() {
  35. memset(head + , -, n * sizeof(int));
  36. ecnt = ;
  37. }
  38.  
  39. void add_edge(int u, int v) {
  40. to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
  41. to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
  42. }
  43.  
  44. void gethash(int a[], int n) {
  45. static int tmp[MAXV];
  46. int cnt = ;
  47. for(int i = ; i <= n; ++i) tmp[cnt++] = a[i];
  48. sort(tmp, tmp + cnt);
  49. cnt = unique(tmp, tmp + cnt) - tmp;
  50. for(int i = ; i <= n; ++i)
  51. a[i] = lower_bound(tmp, tmp + cnt, a[i]) - tmp + ;
  52. }
  53.  
  54. void read() {
  55. scanf("%d%d", &n, &m);
  56. for(int i = ; i <= n; ++i) scanf("%d", &val[i]);
  57. gethash(val, n);
  58. init();
  59. for(int i = , u, v; i < n; ++i) {
  60. scanf("%d%d", &u, &v);
  61. add_edge(u, v);
  62. }
  63. for(int i = ; i < m; ++i) ask[i].read(i);
  64. }
  65. /// find_block
  66. void add_block(int &cnt) {
  67. while(cnt--) block[stk[--top]] = bcnt;
  68. bcnt++;
  69. cnt = ;
  70. }
  71.  
  72. void rest_block() {
  73. while(top) block[stk[--top]] = bcnt - ;
  74. }
  75.  
  76. int dfs_block(int u, int f) {
  77. int size = ;
  78. for(int p = head[u]; ~p; p = next[p]) {
  79. int v = to[p];
  80. if(v == f) continue;
  81. size += dfs_block(v, u);
  82. if(size >= bsize) add_block(size);
  83. }
  84. stk[top++] = u;
  85. size++;
  86. if(size >= bsize) add_block(size);
  87. return size;
  88. }
  89.  
  90. void init_block() {
  91. bsize = max(, (int)sqrt(n));
  92. dfs_block(, );
  93. rest_block();
  94. }
  95. /// ask_rmq
  96. int fa[MLOG][MAXV];
  97. int dep[MAXV];
  98.  
  99. void dfs_lca(int u, int f, int depth) {
  100. dep[u] = depth;
  101. fa[][u] = f;
  102. for(int p = head[u]; ~p; p = next[p]) {
  103. int v = to[p];
  104. if(v != f) dfs_lca(v, u, depth + );
  105. }
  106. }
  107.  
  108. void init_lca() {
  109. dfs_lca(, -, );
  110. for(int k = ; k + < MLOG; ++k) {
  111. for(int u = ; u <= n; ++u) {
  112. if(fa[k][u] == -) fa[k + ][u] = -;
  113. else fa[k + ][u] = fa[k][fa[k][u]];
  114. }
  115. }
  116. }
  117.  
  118. int ask_lca(int u, int v) {
  119. if(dep[u] < dep[v]) swap(u, v);
  120. for(int k = ; k < MLOG; ++k) {
  121. if((dep[u] - dep[v]) & ( << k)) u = fa[k][u];
  122. }
  123. if(u == v) return u;
  124. for(int k = MLOG - ; k >= ; --k) {
  125. if(fa[k][u] != fa[k][v])
  126. u = fa[k][u], v = fa[k][v];
  127. }
  128. return fa[][u];
  129. }
  130. /// modui
  131. bool vis[MAXV];
  132. int diff, cnt[MAXV];
  133.  
  134. void xorNode(int u) {
  135. if(vis[u]) vis[u] = false, diff -= (--cnt[val[u]] == );
  136. else vis[u] = true, diff += (++cnt[val[u]] == );
  137. }
  138.  
  139. void xorPathWithoutLca(int u, int v) {
  140. if(dep[u] < dep[v]) swap(u, v);
  141. while(dep[u] != dep[v])
  142. xorNode(u), u = fa[][u];
  143. while(u != v)
  144. xorNode(u), u = fa[][u],
  145. xorNode(v), v = fa[][v];
  146. }
  147.  
  148. void moveNode(int u, int v, int taru, int tarv) {
  149. xorPathWithoutLca(u, taru);
  150. xorPathWithoutLca(v, tarv);
  151. //printf("debug %d %d\n", ask_lca(u, v), ask_lca(taru, tarv));
  152. xorNode(ask_lca(u, v));
  153. xorNode(ask_lca(taru, tarv));
  154. }
  155.  
  156. void make_ans() {
  157. for(int i = ; i < m; ++i) ask[i].adjust();
  158. sort(ask, ask + m);
  159. int nowu = , nowv = ; xorNode();
  160. for(int i = ; i < m; ++i) {
  161. moveNode(nowu, nowv, ask[i].u, ask[i].v);
  162. ans[ask[i].id] = diff;
  163. nowu = ask[i].u, nowv = ask[i].v;
  164. }
  165. }
  166.  
  167. void print_ans() {
  168. for(int i = ; i < m; ++i)
  169. printf("%d\n", ans[i]);
  170. }
  171.  
  172. void solve() {
  173. read();
  174. init_block();
  175. init_lca();
  176. make_ans();
  177. print_ans();
  178. }
  179.  
  180. };
  181.  
  182. int main() {
  183. Bilibili::solve();
  184. }

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

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

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

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

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

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

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

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

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

  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. SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

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

  9. SPOJ COT2 Count on a tree II (树上莫队)

    题目链接:http://www.spoj.com/problems/COT2/ 参考博客:http://www.cnblogs.com/xcw0754/p/4763804.html上面这个人推导部分写 ...

随机推荐

  1. 在Vista或更高版本Windows系统中, 获取超大图标的办法

    这几天写个小东西, 需要获取系统正在运行的程序图标, 一般来说32*32就足够了, 不过既然Win7能够支持超大图标(256*256), 咱们也需要与时俱进, 说不定什么时候遇到个变态客户就有这要求了 ...

  2. jfinal

    http://blog.csdn.net/zb0567/article/details/21083021

  3. 日志案例分析(PV,UV),以及动态分区

    1.实现的流程 需求分析 时间:日,时段 分区表:两级 PV UV 数据清洗 2015-08-28 18:19:10 字段:id,url,guid,tracktime 数据分析 导出 2.新建源数据库 ...

  4. java整合spring和hadoop HDFS

    http://blog.csdn.net/kokjuis/article/details/53586406 http://download.csdn.net/detail/kokjuis/970932 ...

  5. Provisioning Profile

    什么是Provisioning Profile? 从字面翻译,Provisioning Profile就是配置文件的意思,它在开发者账号体系中所扮演的角色也是配置和验证的作用.如果你有开发者账号,可以 ...

  6. eclipse有时候会报错:Cannot change version of project facet Dynamic Web Module to 2.5。这个错误不会影响程序的运行,不过看着总是不舒服。这个问题现在可以解决啦。

    把项目WEB-INF底下的web.xml文件头部的:     <?xml version="1.0" encoding="UTF-8"?> < ...

  7. 经常在eclipse中导入web项目时,出现转不了项目类型的问题,导入后就是一个java项目。

    1.在eclipse的项目上点右键,刷新项目.2.在项目上点右键,进入属性(properties)3.在左侧列表项目中点击选择“Project Facets”,在右侧选择“Dynamic Web Mo ...

  8. new和delete malloc和free

    程序中动态分配的对象存放在自由存储区(free store)或堆(heap). C语言程序使用一对标准库函数malloc和free在自由存储区中分配存储空间,而C++语言则使用new和delete表达 ...

  9. httpd.conf

    修改配置文件-时会弹出一个文本式的文件 1.搜索:#LoadModule rewrite_module modules/mod_rewrite.so,去掉前面的# 2.全部替换AllowOverrid ...

  10. C++经典编程题#4:单词翻转

    总时间限制:  1000ms  内存限制:  65536kB 描述 输入一个句子(一行),将句子中的每一个单词翻转后输出. 输入 只有一行,为一个字符串,不超过500个字符.单词之间以空格隔开. 输出 ...