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

参考博客:http://www.cnblogs.com/xcw0754/p/4763804.html
上面这个人推导部分写的简洁明了,方便理解,但是最后的分情况讨论有些迷,感觉是不必要的,更简洁的思路看下面的博客

传送门:http://blog.csdn.net/kuribohg/article/details/41458639

题意是这样的,给你一棵无根树,给你m个查询,每次查询输出节点x到节点y路径上不同颜色的节点有多少个(包括xy)

没什么说的,直接上代码吧

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<vector>
  7. using namespace std;
  8. int const MAX_N=+;
  9. int const MAX_M=+;
  10. int n,m,ans,nowLca,lastL,lastR,tempAns;
  11. int color[MAX_N];
  12. vector<int> allColor;
  13. vector<int>::iterator it;
  14. int lin[MAX_N],e_cnt;
  15. struct Query{
  16. int x;
  17. int y;
  18. int id;
  19. int ans;
  20. }query[MAX_M];
  21. struct Edge{
  22. int next;
  23. int y;
  24. }e[*MAX_N];
  25. void insert(int u,int v){
  26. e[++e_cnt].next=lin[u];
  27. e[e_cnt].y=v;
  28. lin[u]=e_cnt;
  29. }
  30. int b_len,b_cnt,bk[MAX_N];
  31. int fa[MAX_N][],deep[MAX_N];
  32. int n_cnt,dfn[MAX_N],top,stack[MAX_N];
  33. bool vis[MAX_N];
  34. void dfs(int u){
  35. dfn[u]=++n_cnt;
  36. int btm=top;
  37. for(int i=lin[u];i;i=e[i].next){
  38. int v=e[i].y;
  39. if(!dfn[v]){
  40. fa[v][]=u;
  41. deep[v]=deep[u]+;
  42. dfs(v);
  43. if(top-btm>=b_len){
  44. b_cnt++;
  45. while(top>btm){
  46. bk[stack[top--]]=b_cnt;
  47. }
  48. }
  49. }
  50. }
  51. stack[++top]=u;
  52. }
  53. bool queryCmp_xkb_ydfn(Query a,Query b){
  54. if(bk[a.x]==bk[b.x])return dfn[a.y]<dfn[b.y];
  55. return bk[a.x]<bk[b.x];
  56. }
  57. bool queryCmp_id(Query a,Query b){
  58. return a.id<b.id;
  59. }
  60. int lca(int u,int v){
  61. if(deep[u]<deep[v])swap(u,v);
  62. for(int i=;~i;i--)
  63. if(deep[fa[u][i]]>=deep[v])
  64. u=fa[u][i];
  65. if(u == v) return u;
  66. for(int i=;~i;i--)
  67. if(fa[u][i]!=fa[v][i])
  68. u=fa[u][i],v=fa[v][i];
  69. return fa[u][];
  70. }
  71. int c_cnt[MAX_N];
  72. void MoveToLca(int u){
  73. for(;u!=nowLca;u=fa[u][]){
  74. if(vis[u]){
  75. vis[u]=false;
  76. c_cnt[color[u]]--;
  77. if(!c_cnt[color[u]])ans--;
  78. }else{
  79. vis[u]=true;
  80. if(!c_cnt[color[u]])ans++;
  81. c_cnt[color[u]]++;
  82. }
  83. }
  84. }
  85. int GetAns(int x,int u,int v){
  86. int tlca=lca(u,v);
  87. if(c_cnt[color[tlca]])return x;
  88. else return x+;
  89. }
  90.  
  91. void FirstMo(){
  92. int L=query[].x,R=query[].y;
  93. nowLca=lca(L,R);
  94. MoveToLca(L);
  95. MoveToLca(R);
  96. query[].ans=GetAns(ans,L,R);
  97. lastL=L;lastR=R;
  98. }
  99. int main()
  100. {
  101. while(~scanf("%d%d",&n,&m)){
  102. allColor.clear();
  103. //read colors
  104. for(int i=;i<=n;i++){
  105. scanf("%d",&color[i]);
  106. allColor.push_back(color[i]);
  107. }
  108. //Discretization the color
  109. sort(allColor.begin(),allColor.end());
  110. it=unique(allColor.begin(),allColor.end());
  111. allColor.resize(distance(allColor.begin(),it));
  112. for(int i=;i<=n;i++){
  113. color[i]=lower_bound(allColor.begin(),allColor.end(),color[i])-allColor.begin()+;
  114. }
  115. //read the tree
  116. memset(lin,,sizeof(lin));
  117. e_cnt=;
  118. for(int i=;i<n;i++){
  119. int u,v;
  120. scanf("%d%d",&u,&v);
  121. insert(u,v);
  122. insert(v,u);
  123. }
  124. //divide in blocks
  125. //prepare for lca: get deep, dfs order, get father
  126. b_len=sqrt((double)n);
  127. b_cnt=;
  128. n_cnt=;
  129. top=;
  130. deep[]=,deep[]=;
  131. memset(fa,,sizeof(fa));
  132. memset(dfn,,sizeof(dfn));
  133. memset(vis,,sizeof(vis));
  134. memset(stack,,sizeof(stack));
  135. dfs();
  136. b_cnt++;
  137. while(top){
  138. bk[stack[top--]]=b_cnt;
  139. }
  140. for(int i = ; (<<i) <= n; i++)
  141. for(int j = ; j <= n; j++)
  142. fa[j][i] = fa[fa[j][i-]][i-];
  143. //read the query
  144. for(int i=;i<=m;i++){
  145. scanf("%d%d",&query[i].x,&query[i].y);
  146. query[i].id=i;
  147. if(dfn[query[i].x]>dfn[query[i].y])
  148. swap(query[i].x,query[i].y);
  149. }
  150. //mo's algorithm
  151. sort(query+,query+m+,queryCmp_xkb_ydfn);
  152. memset(vis,,sizeof(vis));
  153. memset(c_cnt,,sizeof(c_cnt));
  154. lastL=,lastR=,ans=;
  155. for(int i=;i<=m;i++){
  156. int L=query[i].x,R=query[i].y;
  157. nowLca=lca(L,lastL);
  158. MoveToLca(L);
  159. MoveToLca(lastL);
  160. nowLca=lca(R,lastR);
  161. MoveToLca(R);
  162. MoveToLca(lastR);
  163. query[i].ans=GetAns(ans,L,R);
  164. lastL=L;lastR=R;
  165. }
  166. sort(query+,query+m+,queryCmp_id);
  167. for(int i=;i<=m;i++){
  168. printf("%d\n",query[i].ans);
  169. }
  170. }
  171. return ;
  172. }

wa了无数发,最后发现是dfs的时候用vis数组判断点是否访问过,结果忘记初始化vis[1]了。。。。好蠢,后来改成了直接用dfn数组判断是否访问过了,本意是节省资源,结果居然A了。。。人生处处是惊喜。

这里顺便总结下lca写法吧。

这里的是倍增法求LCA

int fa[MAX_N][20],deep[MAX_N];
int dfn[MAX_N];

void dfs(int u){
    dfn[u]=++n_cnt;
    for(int i=lin[u];i;i=e[i].next){
        int v=e[i].y;
        if(!dfn[v]){
            fa[v][0]=u;
            deep[v]=deep[u]+1;
            dfs(v);
        }
    }
}
int lca(int u,int v){
    if(deep[u]<deep[v])swap(u,v);
    for(int i=17;~i;i--)
        if(deep[fa[u][i]]>=deep[v])
            u=fa[u][i];
    if(u == v) return u;
    for(int i=17;~i;i--)
        if(fa[u][i]!=fa[v][i])
            u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}

int main()
{
        n_cnt=0;
        deep[0]=0,deep[1]=1;
        memset(fa,0,sizeof(fa));
        memset(dfn,0,sizeof(dfn));
        dfs(1);

for(int i = 1; (1<<i) <= n; i++)
            for(int j = 1; j <= n; j++)
                fa[j][i] = fa[fa[j][i-1]][i-1];
            return 0;
}

dfn换成vis也是一样的

首先初始化deep数组表示节点深度,然后是fa[i][j]表示节点i的第2^j的父亲节点是什么,

先dfs求出deep和直系父亲

然后双重循环处理fa数组

lca的时候,先对齐u和v,就是让他们处于同一深度,然后一起向上,直到lca的儿子为止,返回他的父亲,就是lca。

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/ You are given a tree with N nodes.The tree nodes are numbere ...

随机推荐

  1. guice基本使用,配置模块的两种方式(三)

    guice是使用module进行绑定的,它提供了两种方式进行操作. 第一种是继承AbstractModule抽象类. package com.ming.user.test; import com.go ...

  2. idiom的学习笔记(一)、三栏布局

    三栏布局左右固定,中间自适应是网页中常用到的,实现这种布局的方式有很多种,这里我主要写五种.他们分别是浮动.定位.表格.flexBox.网格. 在这里也感谢一些老师在网上发的免费教程,使我们学习起来更 ...

  3. 干货 | TensorFlow的55个经典案例

    转自1024深度学习 导语:本文是TensorFlow实现流行机器学习算法的教程汇集,目标是让读者可以轻松通过清晰简明的案例深入了解 TensorFlow.这些案例适合那些想要实现一些 TensorF ...

  4. [ Linux ] [ OS ] [ memory ] Linux 如何查看系統硬體的記憶體(RAM)資訊

    cat /proc/meminfo https://blog.longwin.com.tw/2013/05/linux-ram-memory-info-2013/

  5. vue 返回上一页在原来的位置

    http://www.jb51.net/article/118592.htm http://blog.csdn.net/qq_26598303/article/details/51189235 htt ...

  6. PIC EEPROM问题

    1.通过export出来的Hex烧录,EEPROM内容会根据Hex中关于EEPROM的定义而改变. 2.通过编译源文件烧录,如果没有勾选Preserve EEPROM on program则EEPRO ...

  7. 杭电2602 Bone Collector 【01背包】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602 解题思路:给出一个容量为V的包,以及n个物品,每一个物品的耗费的费用记作c[i](即该物品的体积 ...

  8. 【从零开始】【Java】【1】Git和svn

    闲聊 干活快一年了吧,感觉工作中能干的事情也有一点了,但总有种不通透的感觉,查一个问题,能一路查出一堆不明白的东西. 之前新建过文档是记录点点滴滴的知识的,使用上没问题了,但原理什么的还是不懂,想了想 ...

  9. RxSwift源码与模式分析一:基本类

    封装.变换与处理 // Represents a push style sequence. public protocol ObservableType : ObservableConvertible ...

  10. 执行opatch apply 报错 OPatch failed with error code 73

    .执行opatch apply 报错 OPatch failed [oracle@ora_11g 14275605]$ /opt/oracle/product/db_1/OPatch/opatch a ...