题意:

给出一棵\(n(n \leq 4 \times 10^4)\)个节点的树,每个节点上有个权值,和\(m(m \leq 10^5)\)个询问。

每次询问路径\(u \to v\)上有多少个权值不同的点。

分析:

  • 树分块

首先将树分块,每块的大小为\(\sqrt{n}\)左右。

然后将询问离线处理,按照区间上的莫队算法将询问按块排序。

这里有一道裸的树分块的题目。

  • 树上的路径转移

定义\(S(u,v)\)表示路径\(u \to v\)上的点集,定义\(\bigoplus\)为集合的对称差,类似于异或运算。

那么有\(S(u,v)=S(root,u) \bigoplus S(root, v) \bigoplus LCA(u,v)\),有一个\(LCA\)不方便处理。

再定义一个\(T(u,v)=S(root,u) \bigoplus S(root, v)\)

\(T(u_1, v_1) \bigoplus T(v_1, v_2)=S(root, u_1) \bigoplus S(root, v_1) \bigoplus S(root, v_1) \bigoplus S(root, v_2)\)

消去中间两项得到:\(T(u_1, v_1) \bigoplus T(v_1, v_2)=S(root, u_1) \bigoplus S(root, v_2)=T(u_1, v_2)\)

从结论可以看出,由\(T(u_1,v_1)\)到\(T(u_1, v_2)\)只需要\(\bigoplus\)一个\(T(v_1, v_2)\)。

由于对称差\(\bigoplus\)运算满足交换律和结合律,所以再\(\bigoplus\)一个\(T(u_1, u_2)\)就得到\(T(u_2,v_2)\)。

假设上次查询的路径为\(u \to v\),我们维护点集\(T(u,v)\)的信息:\(in(u)\)点\(u\)是否在集合中,\(cnt(x)\)集合中权值为\(x\)点的个数,\(diff\)权值不同的点数。

查询的话如果\(LCA(u,v)\)的权值没有出现过,答案就是\(diff+1\),否则就是\(diff\)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std; const int maxn = 40000 + 10;
const int maxq = 100000 + 10; struct Edge
{
int v, nxt;
Edge() {}
Edge(int v, int nxt): v(v), nxt(nxt) {}
}; int ecnt, head[maxn];
Edge edges[maxn * 2]; void AddEdge(int u, int v) {
edges[ecnt] = Edge(v, head[u]);
head[u] = ecnt++;
} int n, m; int a[maxn], b[maxn], tot; int anc[maxn][20], dep[maxn];
int group[maxn], blocks, sz; int S[maxn], top; void dfs(int u) {
int cur = top;
for(int i = head[u]; ~i; i = edges[i].nxt) {
int v = edges[i].v;
if(v == anc[u][0]) continue;
anc[v][0] = u;
dep[v] = dep[u] + 1;
dfs(v);
if(top - cur >= sz) {
blocks++;
while(top != cur) group[S[top--]] = blocks;
}
}
S[++top] = u;
} struct Query
{
int u, v, id;
bool operator < (const Query& t) const {
return group[u] < group[t.u] || (group[u] == group[t.u] && group[v] < group[t.v]);
}
}q[maxq]; void preprocess() {
for(int j = 1; (1 << j) < n; j++)
for(int i = 1; i <= n; i++) if(anc[i][j-1])
anc[i][j] = anc[anc[i][j-1]][j-1];
} int LCA(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
int log;
for(log = 0; (1 << log) < dep[u]; log++);
for(int i = log; i >= 0; i--)
if(dep[u] - (1<<i) >= dep[v]) u = anc[u][i];
if(u == v) return u;
for(int i = log; i >= 0; i--)
if(anc[u][i] && anc[u][i] != anc[v][i])
u = anc[u][i], v = anc[v][i];
return anc[u][0];
} int cnt[maxn], dif, in[maxn]; void xorvertex(int u) {
if(in[u]) { cnt[a[u]]--; if(!cnt[a[u]]) dif--; }
else { cnt[a[u]]++; if(cnt[a[u]] == 1) dif++; }
in[u] ^= 1;
} void xorpath(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
while(dep[u] > dep[v]) { xorvertex(u); u = anc[u][0]; }
while(u != v) {
xorvertex(u); xorvertex(v);
u = anc[u][0]; v = anc[v][0];
}
} int ans[maxq]; int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", a + i);
b[i] = a[i];
}
sort(b + 1, b + 1 + n);
tot = unique(b + 1, b + 1 + n) - b - 1;
for(int i = 1; i <= n; i++)
a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b; ecnt = 0;
memset(head, -1, sizeof(head));
for(int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
AddEdge(u, v); AddEdge(v, u);
} sz = (int)sqrt(n);
dfs(1);
while(top) group[S[top--]] = blocks;
preprocess(); for(int i = 1; i <= m; i++) {
scanf("%d%d", &q[i].u, &q[i].v);
q[i].id = i;
if(q[i].u > q[i].v) swap(q[i].u, q[i].v);
} sort(q + 1, q + 1 + m); int u = 1, v = 1;
for(int i = 1; i <= m; i++) {
xorpath(u, q[i].u);
xorpath(v, q[i].v);
u = q[i].u, v = q[i].v;
int lca = LCA(u, v);
ans[q[i].id] = dif;
if(!cnt[a[lca]]) ans[q[i].id]++;
} for(int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0;
}

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. 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]Count on a tree II(树上莫队)

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

  5. 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  ...

  6. 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 ...

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

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

  8. 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 ...

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

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

随机推荐

  1. Java函数的传参机制

    一 最近的一个项目,里面各种返回void,参数用引用类型,那叫一个熟和多,但是也把我绕糊涂了. 我就打算好好理一理java的传参机制,整理一番 二 很多人一听Java的传参,那一定会脱口而出,java ...

  2. WinForm 开发框架 Jade UI Beta

    Jade UI Demo Beta 个人网站:http://www.2to.net 开源地址:https://github.com/dcdlove/JadeUI 预览DEMO下载: http://pa ...

  3. Guice入门

    参考链接:http://www.cnblogs.com/xd502djj/archive/2012/06/25/2561414.html Google Guice范例解说之使用入门 http://co ...

  4. ”position”之绝对定位深入理解

    要点: 1.绝对元素脱离文档流 它从文档流中脱离了出来,后面的元素会填充掉它原来的位置 2.绝对定位元素定位 以离他最近的.有定位的.祖先元素 为准 参照对象决定元素的位置 情况1 <div ( ...

  5. 我们为什么要看《超实用的HTML代码段》

    不知道自己HTML水平如何,不知道HTML5如何进化?看这张图 如果一半以上的你都不会,必须看这本书,阿里一线工程师用代码和功能页面来告诉你每一个技术点. 都会一点,但不知道如何检验自己,看看本书提供 ...

  6. POJ 1845 Sumdiv (数学,乘法逆元)

    题意: 给出数字A和B,要求AB的所有因子(包括AB和1)之和 mod 9901 的结果. 思路: 即使知道公式也得推算一阵子. 很容易知道,先把分解得到,那么得到,那么的所有因子之和的表达式如下: ...

  7. UVA 818 Cutting Chains 切断圆环链 (暴力dfs)

    题意就是给一张无向图,去掉某些结点,然后连成一条链,问最少去掉几个结点. n很小n<=15,所以直接枚举2^15个状态就行啦. 链的条件是1.无环,2.没有度大于2的点,3.把n个散链连起来需要 ...

  8. [神经网络]一步一步使用Mobile-Net完成视觉识别(四)

    1.环境配置 2.数据集获取 3.训练集获取 4.训练 5.调用测试训练结果 6.代码讲解 本文是第四篇,下载预训练模型并训练自己的数据集. 前面我们配置好了labelmap,下面我们开始下载训练好的 ...

  9. git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug

    git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug

  10. 超全面Java 面试题(2.1)

    这部分主要是开源JavaEE框架方面的内容,包括hibernate.MyBatis.spring.Spring MVC等,由于Struts2已经是明日黄花,在这里就不讨论Struts2的面试题,此外, ...