http://www.lydsy.com/JudgeOnline/problem.php?id=3757

题意:n个节点的树,每个点有一种颜色。现有m种询问,每次询问x y a b表示x到y的路径上颜色的种数且a颜色看成b颜色。(n<=50000, m<=100000)

dfs序序列分块战术核导弹= =:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=50005, M=100005;
  4. inline int getint() { int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') (x*=10)+=c-'0', c=getchar(); return x; }
  5. int ihead[N], cnt, blo[N], f[N][16], FF[N], LL[N], tot, dep[N], cal[N], pos[N<<1], col[N], st[N], n, m, Ans[M], ans;
  6. struct E { int next, to; }e[N<<1];
  7. struct Q { int x, y, lca, a, b, id; }q[M];
  8. bool cmp(const Q &a, const Q &b) { return blo[a.x]==blo[b.x]?a.y<b.y:blo[a.x]<blo[b.x]; }
  9. void add(int x, int y) { e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], x}; ihead[y]=cnt; }
  10. void dfs(int x) {
  11. pos[FF[x]=++tot]=x;
  12. for(int i=1; i<=15; ++i) f[x][i]=f[f[x][i-1]][i-1];
  13. for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=f[x][0])
  14. dep[e[i].to]=dep[x]+1, f[e[i].to][0]=x, dfs(e[i].to);
  15. pos[LL[x]=++tot]=x;
  16. }
  17. int LCA(int x, int y) {
  18. if(dep[x]<dep[y]) swap(x, y);
  19. int d=dep[x]-dep[y];
  20. for(int i=15; i>=0; --i) if((d>>i)&1) x=f[x][i]; if(x==y) return x;
  21. for(int i=15; i>=0; --i) if(f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
  22. return f[x][0];
  23. }
  24. void update(int x) {
  25. if(st[x]) { if(!(--cal[col[x]])) --ans; }
  26. else { if(!(cal[col[x]]++)) ++ans; }
  27. st[x]=!st[x];
  28. }
  29. bool check(int a, int b) { return cal[a] && cal[b] && a!=b; } //a!=b
  30. void pre() {
  31. dfs((n+1)>>1);
  32. for(int i=1; i<=m; ++i) {
  33. q[i].x=getint(); q[i].y=getint(); q[i].a=getint(); q[i].b=getint(); q[i].id=i;
  34. if(FF[q[i].x]>FF[q[i].y]) swap(q[i].x, q[i].y);
  35. int lca=LCA(q[i].x, q[i].y);
  36. q[i].y=FF[q[i].y];
  37. if(lca==q[i].x) q[i].x=FF[q[i].x], q[i].lca=0;
  38. else q[i].x=LL[q[i].x], q[i].lca=lca;
  39. }
  40. int nn=n<<1, sq=sqrt(nn+0.5);
  41. for(int i=1; i<=nn; ++i) blo[i]=(i-1)/sq;
  42. sort(q+1, q+1+m, cmp);
  43. }
  44. void work() {
  45. int l=1, r=0, nl, nr;
  46. for(int i=1; i<=m; ++i) {
  47. nl=q[i].x; nr=q[i].y;
  48. while(l<nl) update(pos[l++]);
  49. while(l>nl) update(pos[--l]);
  50. while(r<nr) update(pos[++r]);
  51. while(r>nr) update(pos[r--]);
  52. if(q[i].lca) update(q[i].lca);
  53. Ans[q[i].id]=ans-check(q[i].a, q[i].b);
  54. if(q[i].lca) update(q[i].lca);
  55. }
  56. for(int i=1; i<=m; ++i) printf("%d\n", Ans[i]);
  57. }
  58. int main() {
  59. n=getint(); m=getint();
  60. for(int i=1; i<=n; ++i) col[i]=getint();
  61. for(int i=1; i<=n; ++i) {
  62. int x, y; x=getint(); y=getint();
  63. if(!x || !y) continue;
  64. add(x, y);
  65. }
  66. pre();
  67. work();
  68. return 0;
  69. }

  

无脑dfs序/分块树 树上分块= =

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=50005, M=100005;
  4. int ihead[N], cnt, id[N], blo[N], f[N][16], dep[N], cal[N], col[N], st[N], n, m, Ans[M], ans, ID, n_blo, n_bl, sta[N], top;
  5. struct E { int next, to; }e[N<<1];
  6. struct Q { int x, y, a, b, id; }q[M];
  7. bool cmp(const Q &a, const Q &b) { return blo[a.x]==blo[b.x]?id[a.y]<id[b.y]:blo[a.x]<blo[b.x]; }
  8. void add(int x, int y) { e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], x}; ihead[y]=cnt; }
  9. void dfs(int x) {
  10. id[x]=++ID;
  11. int last=top;
  12. for(int i=1; i<=15; ++i) f[x][i]=f[f[x][i-1]][i-1];
  13. for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=f[x][0]) {
  14. dep[e[i].to]=dep[x]+1; f[e[i].to][0]=x;
  15. dfs(e[i].to);
  16. if(top-last>=n_blo) { ++n_bl; while(top!=last) blo[sta[top--]]=n_bl; }
  17. }
  18. sta[++top]=x;
  19. }
  20. int LCA(int x, int y) {
  21. if(dep[x]<dep[y]) swap(x, y);
  22. int d=dep[x]-dep[y];
  23. for(int i=15; i>=0; --i) if((d>>i)&1) x=f[x][i]; if(x==y) return x;
  24. for(int i=15; i>=0; --i) if(f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
  25. return f[x][0];
  26. }
  27. void update(int x) {
  28. if(st[x]) { if(!(--cal[col[x]])) --ans; }
  29. else { if(!cal[col[x]]) ++ans; ++cal[col[x]]; }
  30. st[x]=!st[x];
  31. }
  32. void move(int x, int y) {
  33. while(x!=y)
  34. if(dep[x]>dep[y]) update(x), x=f[x][0];
  35. else update(y), y=f[y][0];
  36. }
  37. bool check(int a, int b) { return cal[a] && cal[b] && a!=b; } //a!=b
  38. void pre() {
  39. n_blo=sqrt(n+0.5);
  40. dfs(1);
  41. while(top) blo[sta[top--]]=n_bl;
  42. for(int i=1; i<=m; ++i) { scanf("%d%d%d%d", &q[i].x, &q[i].y, &q[i].a, &q[i].b), q[i].id=i; if(id[q[i].x]>id[q[i].y]) swap(q[i].x, q[i].y); }
  43. sort(q+1, q+1+m, cmp);
  44. q[0].x=q[0].y=1;
  45. }
  46. void work() {
  47. for(int i=1; i<=m; ++i) {
  48. move(q[i-1].x, q[i].x); move(q[i-1].y, q[i].y);
  49. int lca=LCA(q[i].x, q[i].y);
  50. update(lca);
  51. Ans[q[i].id]=ans;
  52. if(check(q[i].a, q[i].b)) --Ans[q[i].id];
  53. update(lca);
  54. }
  55. for(int i=1; i<=m; ++i) printf("%d\n", Ans[i]);
  56. }
  57. int main() {
  58. scanf("%d%d", &n, &m);
  59. for(int i=1; i<=n; ++i) scanf("%d", &col[i]);
  60. for(int i=1; i<=n; ++i) {
  61. int x, y; scanf("%d%d", &x, &y);
  62. if(!x || !y) continue;
  63. add(x, y);
  64. }
  65. pre();
  66. work();
  67. return 0;
  68. }

upd:第二种写法:dfs序直接在序列中莫队= =

将树上的点转化为括号序列:每一个点的括号中包含了所有子树的节点:

可以得到:

(FF表示第一个括号的位置,LL表示第二个括号的位置)

当lca(x, y)!=x && !=y时且FF[x]<FF[y]时

  • 区间[LL[x], FF[y]]出现奇数个数的节点就是x到y路径上的节点(但不包括lca):
    1. 5由于LL[x]>FF[祖先],所以[LL[x], FF[y]]中必有lca到x路径上的节点。而在这个区间内,lca的其它的非y的子树都会成偶数(FF[a]>FF[x] && LL[a]<FF[y] 或者 LL[a]<FF[x] 或者 FF[a]>FF[y])。
    2. 而这个区间由于只是到FF[y],因此FF[y]的祖先都是奇数次(因为y还没遍历完),所以区间内必有lca到y的路径上的节点(其中路径上的子树由于上边的理由同理),因此最终还剩下个lca,特判一下即可。

当lca(x, y)==x && FF[x]<FF[y],区间[FF[x], FF[y]]表示出现奇数个数的节点就是x到y路径上的节点。和上面差不多的道理= =

所以搞搞就行辣= =速度超快= =

第一种写法:

树上分块= =

首先一开始就强行yy到了dfs序然后分块,后来不知什么鬼我自己不相信这样做能过这题(因为我一开始理解错啦= =假如固定了l,那么r走过的节点数是均摊O(n)的啊= =最多为2n次(进来又出去))

发现题解就是我一开始想的那样= =

可是我忽略了一个问题有木有!在更新lca的时候可能会出问题!自己画图可以得知!反正如果特判的话很难写的样子?

听说vfk神犇有题解我就去膜拜了下= =跪烂

首先设$S(u, v)$表示$u$到$v$路径上的节点集合。令$+$操作表示元素的模2加(即出现次数的模2加法,即异或= =,就是出现两次的就去掉)

容易得到$S(u, v) = S(root, u) + S(root, v) + lca(u, v)$

lca就是最麻烦的,vfk给出了一种巧妙的解法:

设$T(u, v) = S(root, u) + S(root, v)$

则设$u'$表示$u$要到达的目的地:

$$T(u, v) + T(u', v) = S(u, root) + S(u', root) + S(v, root) + S(v, root)$$

$$T(u', v) = T(u, u') + T(u, v)$$

那么我们要从$T(u, v)$转移到$T(u', v)$只需要走一次$T(u, u')$上的点就行辣!(注意踢掉lca)

而不选lca可以直接用向上爬的方法做= =很简单哒= =

然后计数颜色就开个计数器就行辣= =

然后就没辣= =

【BZOJ】3757: 苹果树的更多相关文章

  1. BZOJ 3757: 苹果树

    3757: 苹果树 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1726  Solved: 550[Submit][Status][Discuss] ...

  2. bzoj 3757 苹果树(树上莫队算法)

    [题意] 有若干个询问,询问路径u,v上的颜色总数,另外有要求a,b,意为将a颜色看作b颜色. [思路] vfk真是神系列233. Quote: 用S(v, u)代表 v到u的路径上的结点的集合. 用 ...

  3. BZOJ.3757.苹果树(树上莫队)

    题面链接 /* 代码正确性不保证..(不过交了SPOJ没WA T了最后一个点) 在DFS序做莫队 当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 */ #include <cmath& ...

  4. BZOJ 3757 苹果树 ——莫队算法

    挺好的一道题目,怎么就没有版权了呢?大数据拍过了,精神AC.... 发现几种颜色这性质比较垃圾,不可加,莫队硬上. %了一发popoqqq大神的博客, 看了一波VFK关于糖果公园的博客, 又找了wjm ...

  5. bzoj 3757 树上莫队

    感谢以下文章作者: http://blog.csdn.net/kuribohg/article/details/41458639 http://vfleaking.blog.163.com/blog/ ...

  6. BZOJ - 3757 树上莫队解决离线路径问题 & 学习心得

    题意:给你一棵树,求u,v最短路径的XXX(本题是统计权值种类) 今天课上摸鱼学了一种有意思的处理路径方式(其实是链式块状树翻车了看别的),据说实际运行跑的比XX记者还快 大概就是像序列莫队那样 首先 ...

  7. 【BZOJ】【3757】苹果树

    树分块 orz HZWER http://hzwer.com/5259.html 不知为何我原本写的倍增求LCA给WA了……学习了HZWER的倍增新姿势- 树上分块的转移看vfk博客的讲解吧……(其实 ...

  8. 【BZOJ】3052: [wc2013]糖果公园

    http://www.lydsy.com/JudgeOnline/problem.php?id=3052 题意:n个带颜色的点(m种),q次询问,每次询问x到y的路径上sum{w[次数]*v[颜色]} ...

  9. 【BZOJ-3757】苹果树 块状树 + 树上莫队

    3757: 苹果树 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1305  Solved: 503[Submit][Status][Discuss] ...

随机推荐

  1. 【JAVA基本数据类型包装类】

    一.概述 JAVA中一共有8种数据类型,分别是byte short int long boolean float double  char,与此相对应的,有8个类与它们分别对应: byte Byte ...

  2. 关于WCF的一些注意事项

    1.服务代理,建立通道的方法,要注意及时关掉代理,因为服务设置有一个服务的最大连接数,超过这个连接数,则后面的连接将会等待,一直到超时,报错!! 2.在已有配置的基础上,利用代码更改终结点,如果重设了 ...

  3. PHP日期操作类代码-农历-阳历转换、闰年、计算天数等

    <?php class Lunar { var $MIN_YEAR = 1891; var $MAX_YEAR = 2100; var $lunarInfo = array( array(0,2 ...

  4. PMP 第三章 单个项目的项目管理标准

    1 项目管理五大过程组分别是什么? 启动过程组 规划过程组 执行过程组 监控过程组 收尾过程组 2 启动项目组是干什么?包含哪些过程?每个阶段都需要启动吗? 启动过程组:获得授权,定义一个新项目或现有 ...

  5. Windows phone 8.0 本地化遇到的两个问题

    基本上来说,按照msdn来讲的,本地化和全球化没有太多的问题,链接如下: http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/ff ...

  6. Android开发学习笔记:浅谈WebView(转)

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://liangruijun.blog.51cto.com/3061169/647456 ...

  7. .NET中的六个重要概念:栈、堆、值类型、引用类型、装箱和拆箱

    为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...

  8. Reading and Writing CSV Files in C#

    Introduction A common requirement is to have applications share data with other programs. Although t ...

  9. RecyclerView 介绍 01

    RecyclerView是Android support v7里面是一个自定义控件.用来显示大量数据集合.类似ListView和GridView这两个控件,RecyclerView同样可以实现,甚至更 ...

  10. poj1611 并查集 (路径不压缩)

    http://poj.org/problem?id=1611 题目大意: 有一个学校,有N个学生,编号为0-N-1,现在0号学生感染了非典,凡是和0在一个社团的人就会感染,并且这些人如果还参加了别的社 ...