树上莫队,本地极限数据 1825 ms 通过,交上去 TLE.
LCA 是用树链剖分求的,曾经过了 P3379。
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <algorithm>
#define R register
#define N 40005
#define M 100005
using namespace std;
char Buf[1 << 24], *S(Buf), *T(Buf);
#define getchar() (S == T && (T = (S = Buf) + fread(Buf, 1, 1 << 24, stdin), S == T) ? EOF : *S++)
inline int input() {
R int x(0), f(0);
R char c(getchar());
while (!isdigit(c)) f |= (c == '-'), c = getchar();
while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
int Ans, his[N << 2], Sta[N], End[N], ans[M], n, m, dfn, len, cnt, a[N], buc[N];
struct Query {
int l, r, pos, lca;
inline Query(int _L = 0, int _R = 0, int _Pos = 0, int _LCA = 0) : l(_L), r(_R), pos(_Pos), lca(_LCA) {}
inline bool operator < (const Query &b) {
int Pos(l / len);
if (Pos != b.l / len)
return Pos < b.l / len;
return Pos & 1 ? r < b.r : r > b.r;
}
};
Query Q[M];
int head[N], ver[N << 1], nex[N << 1], tot;
int size[N], deep[N], fa[N], son[N], top[N];
bool vis[N];
inline void add(int x, int y) {
ver[++tot] = y, nex[tot] = head[x], head[x] = tot;
}
void Dfs1(int x, int f) {
his[++dfn] = x, Sta[x] = dfn;
fa[x] = f, size[x] = 1, deep[x] = deep[f] + 1;
for (int i(head[x]), y; i; i = nex[i]) {
if ((y = ver[i]) == f)
continue;
Dfs1(y, x), size[x] += size[y];
if (size[y] > size[son[x]])
son[x] = y;
}
his[++dfn] = x, End[x] = dfn;
}
void Dfs2(int x, int f) {
if (son[x])
top[son[x]] = x, Dfs2(son[x], x);
for (int i(head[x]), y; i; i = nex[i])
if (!top[y = ver[i]])
top[y] = y, Dfs2(y, x);
}
inline void swap(int &a, int &b) {
int t(a);
a = b, b = t;
}
inline int LCA(int x, int y) {
R int tx(top[x]), ty(top[y]);
while (tx != ty) {
if (deep[tx] < deep[ty])
swap(x, y), swap(tx, ty);
x = fa[x], tx = top[x];
}
if (deep[x] > deep[y])
swap(x, y);
return x;
}
struct Data {
int pos, val;
inline Data(int Pos = 0, int Val = 0) : pos(Pos), val(Val) {}
inline bool operator < (const Data &b) { return val < b.val; }
};
Data d[N];
inline void DEL(int x) { Ans -= (--buc[x] == 0); }
inline void ADD(int x) { Ans += (++buc[x] == 1); }
inline void Add(int x) {
vis[x] ? DEL(a[x]) : ADD(a[x]), vis[x] ^= true;
}
int main() {
len = sqrt(n = input()), m = input();
for (int i(1); i <= n; ++i) d[i] = Data(i, input());
sort(d + 1, d + n + 1);
for (int i(1); i <= n; ++i)
if (i == 1 || d[i].val != d[i - 1].val)
a[d[i].pos] = ++cnt;
else
a[d[i].pos] = cnt;
for (int i(1); i < n; ++i) {
int x(input()), y(input());
add(x, y), add(y, x);
}
Dfs1(1, 0), top[1] = 1, Dfs2(1, 0);
for (int i(1); i <= m; ++i) {
int x(input()), y(input());
if (Sta[x] > Sta[y])
swap(x, y);
int lca = LCA(x, y);
if (lca == x)
Q[i] = Query(Sta[x], Sta[y], i);
else
Q[i] = Query(End[x], Sta[y], i, lca);
}
sort(Q + 1, Q + m + 1);
int l = 1, r = 0;
for (int i(1); i <= m; ++i) {
while (l < Q[i].l) Add(his[l]), ++l;
while (l > Q[i].l) Add(his[--l]);
while (r < Q[i].r) Add(his[++r]);
while (r > Q[i].r) Add(his[r]), --r;
if (Q[i].lca)
Add(Q[i].lca);
ans[Q[i].pos] = Ans;
if (Q[i].lca)
Add(Q[i].lca);
}
for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return 0;
}