【BZOJ2589】[SPOJ10707]Count on a tree II

题面

bzoj

题解

这题如果不强制在线就是一个很\(sb\)的莫队了,但是它强制在线啊\(qaq\)

所以我们就用到了另一个东西:树分块

具体是怎么分块的呢:根据深度,从最深的叶子节点往上分,同一子树内的节点在一个块

比如说上面那张图,

有\(7\)个点,那么我们每隔\(2\)的深度就分一块

但是我们又要保证同一子树内的在一块,且要从最深的叶子节点一直往下

所以最后分块的结果:\((1,2)(7,6,3)(4,5)\)。

知道怎么分块了,我们在来考虑怎么做。

现在给了你两个将询问的点\(u,v(dep[u]>dep[v])\),我们分类讨论一下现在的情况:

\((1):\)这两个点在同一个块内:

直接暴力统计即可

\((2):\)这两个点不在同一个块内:

这种情况比较复杂,记一个块的根为\(rt[i]\),则它到另外所有点的答案我们可以很轻松地

统计出来,只需要对于每个\(rt[i]\)暴力统计一遍就可以了。

那么现在我们要考虑的只有\(u\)到它的块的根\(x\)路径上是否会对答案产生贡献:

对于这个,我们可以将这个分块可持久化,维护这个点的颜色在它的祖先中出现最深的位置

的深度,那么一个块只需继承上面的块,并将在这个块中颜色的答案更新,因为那个颜色如

果出现在这个位置,那么答案肯定更优。

有了上面的铺垫,那我们只需对\(u\rightarrow x\)上的点暴力算它的深度是否超过\(lca_{u,v}\)即可

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <algorithm>
  7. using namespace std;
  8. inline int gi() {
  9. register int data = 0, w = 1;
  10. register char ch = 0;
  11. while (!isdigit(ch) && ch != '-') ch = getchar();
  12. if (ch == '-') w = -1, ch = getchar();
  13. while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
  14. return w * data;
  15. }
  16. const int MAX_N = 4e4 + 5;
  17. struct Graph { int to, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
  18. void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
  19. void Add_Edge(int u, int v) { e[e_cnt] = (Graph){v, fir[u]}; fir[u] = e_cnt++; }
  20. int N, M, LEN;
  21. int X[MAX_N], a[MAX_N], b[MAX_N], r[MAX_N];
  22. int P[MAX_N][205], A[205][MAX_N];
  23. int fa[MAX_N], dep[MAX_N], q[MAX_N], belong[MAX_N], cur, sz;
  24. int rt[205], tot;
  25. int c[MAX_N], Res;
  26. struct Block {
  27. int a[205];
  28. int &operator [] (int x) { return P[a[b[x]]][r[x]]; }
  29. void insert(Block rhs, int x, int d) {
  30. int blk = b[x], t = r[x];
  31. memcpy(a, rhs.a, sizeof(a));
  32. memcpy(P[++sz], P[a[blk]], sizeof(P[0]));
  33. P[sz][t] = d, a[blk] = sz;
  34. }
  35. } s[MAX_N];
  36. namespace Tree {
  37. int top[MAX_N], son[MAX_N], size[MAX_N];
  38. void dfs(int x, int tp) {
  39. top[x] = tp;
  40. if (son[x]) dfs(son[x], tp);
  41. for (int i = fir[x]; ~i; i = e[i].next) {
  42. int v = e[i].to; if (v == fa[x] || v == son[x]) continue;
  43. dfs(v, v);
  44. }
  45. }
  46. int LCA(int x, int y) {
  47. while (top[x] != top[y]) {
  48. if (dep[top[x]] < dep[top[y]]) swap(x, y);
  49. x = fa[top[x]];
  50. }
  51. return dep[x] < dep[y] ? x : y;
  52. }
  53. }
  54. int dfs(int x, int f) {
  55. fa[x] = f;
  56. s[x].insert(s[f], a[x], dep[x] = dep[f] + 1);
  57. Tree::size[x] = 1;
  58. q[++cur] = x; int md = dep[x], p = cur;
  59. for (int i = fir[x]; ~i; i = e[i].next) {
  60. int v = e[i].to; if (v == f) continue;
  61. md = max(md, dfs(v, x)); Tree::size[x] += Tree::size[v];
  62. if (Tree::size[Tree::son[x]] < Tree::size[v]) Tree::son[x] = v;
  63. }
  64. if (md - dep[x] >= LEN || p == 1) {
  65. rt[++tot] = x;
  66. for (int i = p; i <= cur; i++) belong[q[i]] = tot;
  67. cur = p - 1;
  68. return dep[x] - 1;
  69. }
  70. return md;
  71. }
  72. void Prepare(int x, int f, int *s) {
  73. if (!c[a[x]]++) ++Res; s[x] = Res;
  74. for (int i = fir[x]; ~i; i = e[i].next) if (e[i].to != f) Prepare(e[i].to, x, s);
  75. if (!--c[a[x]]) --Res;
  76. }
  77. int Solve1(int u, int v) {
  78. for (cur = Res = 0; u != v; u = fa[u]) {
  79. if (dep[u] < dep[v]) swap(u, v);
  80. if (!c[q[++cur] = a[u]]) c[a[u]] = 1, ++Res;
  81. }
  82. for (Res += !c[a[u]]; cur; ) c[q[cur--]] = 0;
  83. return Res;
  84. }
  85. int Solve2(int u, int v) {
  86. if (dep[rt[belong[u]]] < dep[rt[belong[v]]]) swap(u, v);
  87. int x = rt[belong[u]], d = dep[Tree::LCA(u, v)]; Res = A[belong[u]][v];
  88. for (cur = 0; u != x; u = fa[u]) {
  89. if (!c[a[u]] && s[x][a[u]] < d && s[v][a[u]] < d)
  90. c[q[++cur] = a[u]] = 1, ++Res;
  91. }
  92. for (; cur; ) c[q[cur--]] = 0;
  93. return Res;
  94. }
  95. int main () {
  96. clearGraph();
  97. N = gi(), M = gi(); LEN = sqrt(N) - 1;
  98. for (int i = 1; i <= N; i++) b[i] = (i - 1) / LEN + 1, r[i] = i % LEN;
  99. for (int i = 1; i <= N; i++) a[i] = X[i] = gi();
  100. sort(&X[1], &X[N + 1]); int cnt = unique(&X[1], &X[N + 1]) - X - 1;
  101. for (int i = 1; i <= N; i++) a[i] = lower_bound(&X[1], &X[cnt + 1], a[i]) - X;
  102. for (int i = 1; i < N; i++) {
  103. int u = gi(), v = gi();
  104. Add_Edge(u, v);
  105. Add_Edge(v, u);
  106. }
  107. cur = 0;
  108. dfs(1, 0); Tree::dfs(1, 1);
  109. for (int i = 1; i <= tot; i++) Prepare(rt[i], 0, A[i]);
  110. for (int ans = 0; M--; ) {
  111. int u = ans ^ gi(), v = gi();
  112. printf("%d\n", ans = belong[u] == belong[v] ? Solve1(u, v) : Solve2(u, v));
  113. }
  114. return 0;
  115. }

【BZOJ2589】[SPOJ10707]Count on a tree II的更多相关文章

  1. 【树上莫队】【SP10707】 COT2 - Count on a tree II

    Description 给定一棵 \(n\) 个点的树,每个节点有一个权值,\(m\) 次询问,每次查询两点间路径上有多少不同的权值 Input 第一行是 \(n\) 和 \(m\) 第二行是 \(n ...

  2. 【SPOJ10707】 COT2 Count on a tree II

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

  3. 【SPOJ10707】COT2 - Count on a tree II

    题目大意:给定一棵 N 个节点的无根树,每个节点有一个颜色.现有 M 个询问,每次询问一条树链上的不同颜色数. 题解:学会了树上莫队. 树上莫队是将节点按照欧拉序进行排序,将树上问题转化成序列上的问题 ...

  4. 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)

    http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...

  5. bzoj2589: Spoj 10707 Count on a tree II

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

  6. LCA【SP913】Qtree - Query on a tree II

    Description 给定一棵n个点的树,边具有边权.要求作以下操作: DIST a b 询问点a至点b路径上的边权之和 KTH a b k 询问点a至点b有向路径上的第k个点的编号 有多组测试数据 ...

  7. [SPOJ10707]Count on a tree II

    luogu 题意 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. sol 也就是路径数颜色.树上莫队板子题. 我这种分块的姿势貌似是假的. 所以跑的是最慢的QAQ. ...

  8. 【BZOJ2589】 Spoj 10707 Count on a tree II

    BZOJ2589 Spoj 10707 Count on a tree II Solution 吐槽:这道题目简直...丧心病狂 如果没有强制在线不就是树上莫队入门题? 如果加了强制在线怎么做? 考虑 ...

  9. 【SPOJ】Count On A Tree II(树上莫队)

    [SPOJ]Count On A Tree II(树上莫队) 题面 洛谷 Vjudge 洛谷上有翻译啦 题解 如果不在树上就是一个很裸很裸的莫队 现在在树上,就是一个很裸很裸的树上莫队啦. #incl ...

随机推荐

  1. 使用zepto实现QQ消息左滑删除效果

    有这样一个需求: 1. 有一个列表,将每一个列表项左滑动出现删除按钮: 2. 右滑动隐藏删除按钮: 3. 点击这个删除按钮删除该列表项. 完成以后的效果: 这是微信网页端的页面,使用的是 zepto ...

  2. Java基础知识强化之集合框架笔记76:ConcurrentHashMap之 ConcurrentHashMap简介

    1. ConcurrentHashMap简介: ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和Hashtable功能相同但是线程安全的方法.Conc ...

  3. 【HNOI2009】梦幻布丁

    题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式 第一 ...

  4. weblogic远程调试XMLDecoder RCE CVE-2017-10271

    首先说一下远程调试的配置,首先在weblogic的启动文件加入如下配置,开启服务器远程调试端口就是9999: 第二步,建立一个java的空项目. 第三步将weblogic的所有jar包拷出来,放到一个 ...

  5. C/C++——存储

    关于各内存空间: 栈(stack):变量,数组.栈的大小是2M(也有的是1M),反正不大,一般递归写错了,没有出口,都会报错stack overflow. 全局区(静态区):全局变量.数组,静态变量. ...

  6. 使用Jwt为.Net Core SignalR保驾护航

    前言 SignalR Demo搭建起来之后,是没有相应的认证和授权功能的.于是乎,参考官方文档实现了相应的逻辑. 简单认证 首先使用稍微简单的方式实现.添加如下代码: services.AddAuth ...

  7. sping全家桶笔记

    1.curl 用于在终端命令模式下访问一个URL地址 例如在idea的Terminal中访问URL,健康检查(需要加入actuator依赖)curl http://localhost:8080/act ...

  8. STM8 亮灯程序

    开发环境:ST Visual Develop+STM32 ST-LINK Utility+开发板 原理:定时向指定针脚输出高电平信号 /* MAIN.C file * * Copyright (c) ...

  9. nginx发布antd-pro项目(别人发的,未测试)

    server { listen ; server_name localhost; #charset koi8-r; charset utf-; #access_log logs/host.access ...

  10. 指定Android adb的启动端口

    串口执行: setprop service.adb.tcp.port stop adbd start adbd 一般机器默认是5555为adb端口,但是今天遇到的一台机器以5037为默认端口,开发机器 ...