试题描述
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 perform 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.
输入
In the first line there are two integers N and M. (N <= 40000, M <= 100000)
In the second line there are N integers. The i-th integer denotes the weight of the i-th 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.
输出
For each operation, print its result.
输入示例
8 2 105 2 9 3 8 5 7 7 1 2 1 3 1 4 3 5 3 6 3 7 4 8 2 5 7 8
输出示例
4 4
数据规模及约定
见“输入”
题解
树上莫队。
就是树上分块(见上一题);接着对询问路径按照左端点所在块为第一关键字,右端点 dfs 序为第二关键字(随便让哪个点作为左端点都无所谓);然后暴力从一条路径 (a, b) 更新到另一条路径 (a‘, b‘)。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> #include <cmath> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); } return x * f; } #define maxn 50010 #define maxm 100010 #define maxq 100010 #define maxlog 17 int n, m, head[maxn], nxt[maxm], to[maxm], col[maxn], num[maxn]; void AddEdge(int a, int b) { to[++m] = b; nxt[m] = head[a]; head[a] = m; swap(a, b); to[++m] = b; nxt[m] = head[a]; head[a] = m; return ; } int fa[maxn], dep[maxn], mnp[maxlog][maxn<<1], dfn[maxn], clo, Bsiz, blid[maxn], cb, S[maxn], top; void build(int u) { dfn[u] = ++clo; mnp[0][clo] = u; int bot = top; for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u]) { fa[to[e]] = u; dep[to[e]] = dep[u] + 1; build(to[e]); mnp[0][++clo] = u; if(top - bot >= Bsiz) { cb++; while(top > bot) blid[S[top--]] = cb; } } S[++top] = u; return ; } int Log[maxn<<1]; void rmq_init() { Log[1] = 0; for(int i = 2; i <= clo; i++) Log[i] = Log[i>>1] + 1; for(int j = 1; (1 << j) <= clo; j++) for(int i = 1; i + (1 << j) - 1 <= clo; i++) { int a = mnp[j-1][i], b = mnp[j-1][i+(1<<j-1)]; mnp[j][i] = dep[a] < dep[b] ? a : b; } return ; } int lca(int a, int b) { int l = dfn[a], r = dfn[b]; if(l > r) swap(l, r); int t = Log[r-l+1]; a = mnp[t][l]; b = mnp[t][r-(1<<t)+1]; return dep[a] < dep[b] ? a : b; } int q; struct Que { int u, v, id; Que() {} Que(int _1, int _2, int _3): u(_1), v(_2), id(_3) {} bool operator < (const Que& t) const { return blid[u] != blid[t.u] ? blid[u] < blid[t.u] : dfn[v] < dfn[t.v]; } } qs[maxq]; int U, V, ans, tot[maxn], Ans[maxq]; bool tag[maxn]; void rev(int u) { if(tag[u]) { if(!--tot[col[u]]) ans--; } else { if(++tot[col[u]] == 1) ans++; } tag[u] ^= 1; return ; } void change(int& node, int tar) { int c = lca(node, tar), c2 = lca(U, V); bool has = 0; while(node != c) rev(node), node = fa[node]; int ttar = tar; while(tar != c) rev(tar), tar = fa[tar]; rev(c); node = ttar; int c3 = lca(U, V); if(dep[c] < dep[c2]) c = c2; if(dep[c] < dep[c3]) c = c3; rev(c); return ; } int main() { n = read(); q = read(); for(int i = 1; i <= n; i++) num[i] = col[i] = read(); sort(num + 1, num + n + 1); for(int i = 1; i <= n; i++) col[i] = lower_bound(num + 1, num + n + 1, col[i]) - num; for(int i = 1; i < n; i++) { int a = read(), b = read(); AddEdge(a, b); } Bsiz = sqrt(n + .5); build(1); while(top) blid[S[top--]] = cb; rmq_init(); for(int i = 1; i <= q; i++) { int a = read(), b = read(); qs[i] = Que(a, b, i); } sort(qs + 1, qs + q + 1); U = V = ans = tot[col[1]] = tag[1] = 1; for(int i = 1; i <= q; i++) { change(U, qs[i].u); change(V, qs[i].v); Ans[qs[i].id] = ans; } for(int i = 1; i <= q; i++) printf("%d\n", Ans[i]); return 0; }