「计蒜客模拟赛」魔镜啊魔镜

#T3252. 「计蒜客模拟赛」魔镜啊魔镜

Summarize

一棵 $n$ 个节点的树,给定 $m$ 个标记链。进行 $q$ 次询问,每次询问 $(u,v)$ 链上有多少条标记链。

$n\le 100000,m\le 100000,q\le 100000$

Solution

以 $1$ 为根,预处理 $\text{dfs}$ 序。

对于一条标记链 $(u,v)$,如果 $u$、$v$ 存在祖孙关系,则可以推出,如果查询链 $(x,y)$ 完全包含 $(u,v)$,则 $x$、$y$ 分别属于某个区间中。

如果 $u$、$v$ 不存在祖孙关系,则 $x$、$y$ 同样分属在两个区间中。

二维偏序即可处理。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e5 + 5;

struct Node {
int x, y, val, op, idx; // 0: modify 1: query
} node[MAXN << 4];
int node_idx;

bool cmp(Node a, Node b) {
if (a.x != b.x) return a.x < b.x;
if (a.y != b.y) return a.y < b.y;
return a.op < b.op;
}

int n, m, q;
int c[MAXN];

void modify(int p, int val) {
for (; p <= n; p += p & (-p))
c[p] += val;
}

int query(int p) {
int ret = 0;
for (; p; p -= p & (-p))
ret += c[p];
return ret;
}

vector<int> G[MAXN];

int f[MAXN][18], dep[MAXN], dfn[MAXN], siz[MAXN], dfn_idx;

void dfs(int u, int fa) {
f[u][0] = fa, dep[u] = dep[fa] + 1, dfn[u] = ++dfn_idx, siz[u] = 1;
for (int i = 1; i <= 17; ++i)
f[u][i] = f[f[u][i - 1]][i - 1];
for (vector<int>::iterator it = G[u].begin(); it != G[u].end(); it++) {
int v = *it;
if (v == fa) continue;
dfs(v, u);
siz[u] += siz[v];
}
}

int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i = 17; i >= 0; --i)
if (dep[f[u][i]] >= dep[v]) u = f[u][i];
if (u == v) return u;
for (int i = 17; i >= 0; --i)
if (f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
return f[u][0];
}

int jump(int u, int d) {
int k = 0;
while (d) {
if (d & 1) u = f[u][k];
k++;
d >>= 1;
}
return u;
}

int ans[MAXN];

int main() {
freopen("mirror.in", "r", stdin);
freopen("mirror.out", "w", stdout);
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v), G[v].push_back(u);
}
dfs(1, 0);
for (int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
int t = lca(u, v);
if (t == u || t == v) {
if (dep[u] < dep[v]) swap(u, v); // u is deeper
int w = jump(u, dep[u] - dep[v] - 1); // jump to v's son
node[++node_idx] = (Node) {dfn[u], 1, 1, 0, 0};
node[++node_idx] = (Node) {dfn[u], dfn[w], -1, 0, 0};
node[++node_idx] = (Node) {dfn[u], dfn[w] + siz[w], 1, 0, 0};
node[++node_idx] = (Node) {dfn[u] + siz[u], 1, -1, 0, 0};
node[++node_idx] = (Node) {dfn[u] + siz[u], dfn[w], 1, 0, 0};
node[++node_idx] = (Node) {dfn[u] + siz[u], dfn[w] + siz[w], -1, 0, 0};
} else {
node[++node_idx] = (Node) {dfn[u], dfn[v], 1, 0, 0};
node[++node_idx] = (Node) {dfn[u], dfn[v] + siz[v], -1, 0, 0};
node[++node_idx] = (Node) {dfn[u] + siz[u], dfn[v], -1, 0, 0};
node[++node_idx] = (Node) {dfn[u] + siz[u], dfn[v] + siz[v], 1, 0, 0};
}
}
for (int i = 1; i <= q; ++i) {
int u, v;
scanf("%d%d", &u, &v);
node[++node_idx] = (Node) {dfn[u], dfn[v], 0, 1, i};
node[++node_idx] = (Node) {dfn[v], dfn[u], 0, 1, i};
}
sort(node + 1, node + node_idx + 1, cmp);
for (int i = 1; i <= node_idx; ++i) {
if (node[i].op == 1) {
ans[node[i].idx] += query(node[i].y);
} else {
modify(node[i].y, node[i].val);
}
}
for (int i = 1; i <= q; ++i) printf("%d\n", ans[i]);
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×