[BZOJ-3572]世界树

Description

给你一棵n个点的树,m次询问。
每次询问给出一些关键点,树上所有的点被距离它最近的关键点管辖,求每个关键点管辖多少点。
n ≤ 300000, m ≤ 300000, Sigma(关键点个数) <= 300000

Solution

这是一道[HNOI2014]的题。
我们可以用上下DP求出每个点被哪些点管辖,时间复杂度是 O(nm)的。
我们考虑建出虚树,建完虚树后用上下DP处理出虚树上每个点被哪些关键点管辖。
然后我们考虑一个关键点可以管辖哪些点。
对于深度比它大的点,一定是它的子树去掉某些子树。对于深度比它小的点,一定是它的某个祖先的子树去掉它。
我们考虑枚举虚树上的每一条边:如果它两端点不被同一个关键点管辖,则倍增找出一个分界点,然后处理答案即可。

Notice

此题细节较多,处理很麻烦。

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define Rep(i, a, b) for (int i = (a); i < (b); i++)
#define travel(i, u) for (int i = head[u]; ~i; i = edge[i].next)

const ll INF = 1e9, Mo = 998244353;
const int N = 300000;
const double eps = 1e-6;
namespace slow_IO
{
ll read()
{
ll x = 0; int zf = 1; char ch = getchar();
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return x * zf;
}
void write(ll y)
{
if (y < 0) putchar('-'), y = -y;
if (y > 9) write(y / 10);
putchar(y % 10 + '0');
}
}
using namespace slow_IO;

int n, m, edgenum = 0, num, idx;
int head[N + 5], Belong[N + 5], Size[N + 5], Rest[N + 5], Ans[N + 5], Dis[N + 5], Deep[N + 5], Fa[N + 5][20], X[N + 5], Y[N + 5], Z[N + 5], dfn[N + 5], stack[N + 5];
struct node
{
int vet, next;
}edge[2 * N + 5];
void addedge(int u, int v)
{
edge[edgenum].vet = v;
edge[edgenum].next = head[u];
head[u] = edgenum++;
}
int cmp(int x, int y) { return dfn[x] < dfn[y];}

void dfs(int u, int fa)
{
Size[u] = 1, Deep[u] = Deep[fa] + 1, dfn[u] = ++idx, Fa[u][0] = fa;
rep(i, 1, 19) Fa[u][i] = Fa[Fa[u][i - 1]][i - 1];
travel(i, u)
{
int v = edge[i].vet;
if (v == fa) continue;
dfs(v, u);
Size[u] += Size[v];
}
}
int lca(int x, int y)
{
if (Deep[x] < Deep[y]) swap(x, y);
per(i, 19, 0) if (Deep[Fa[x][i]] >= Deep[y]) x = Fa[x][i];
if (x == y) return x;
per(i, 19, 0)
if (Fa[x][i] != Fa[y][i]) x = Fa[x][i], y = Fa[y][i];
return Fa[x][0];
}

void Build()
{
sort(X + 1, X + m + 1, cmp);
int top = 0; stack[++top] = 1;
rep(i, 1, m)
{
if (X[i] == 1) continue;
int u = lca(X[i], stack[top]);
while (top && Deep[stack[top]] > Deep[u])
{
addedge(Deep[stack[top - 1]] < Deep[u] ? u : stack[top - 1], stack[top]);
top--;
}
if (!top || stack[top] != u) stack[++top] = u;
stack[++top] = X[i];
}
while (--top) addedge(stack[top], stack[top + 1]);
}

void up_dfs(int u)
{
Z[++num] = u; Rest[u] = Size[u];
travel(i, u)
{
int v = edge[i].vet;
up_dfs(v);
if (!Belong[v]) continue;
int dis1 = Deep[Belong[v]] - Deep[u], dis2 = Belong[u] ? Deep[Belong[u]] - Deep[u] : INF;
if (dis1 < dis2 || dis1 == dis2 && Belong[v] < Belong[u]) Belong[u] = Belong[v];
}
Dis[u] = Deep[Belong[u]] - Deep[u];
}
void down_dfs(int u)
{
travel(i, u)
{
int v = edge[i].vet;
int dis1 = Dis[u] + Deep[v] - Deep[u], dis2 = Dis[v];
if (dis1 < dis2 || dis1 == dis2 && Belong[u] < Belong[v]) Belong[v] = Belong[u], Dis[v] = dis1;
down_dfs(v);
}
}

void Solve(int u, int v)
{
int mid = v;
if (Belong[u] == Belong[v])
{
Rest[u] -= Size[v];
return;
}
per(i, 19, 0)
{
int x = Fa[mid][i];
if (Deep[x] <= Deep[u]) continue;
int dis1 = Dis[u] + Deep[x] - Deep[u], dis2 = Dis[v] + Deep[v] - Deep[x];
if (dis1 > dis2 || dis1 == dis2 && Belong[u] > Belong[v]) mid = x;
}
Rest[u] -= Size[mid];
Ans[Belong[v]] += Size[mid] - Size[v];
}

int sqz()
{
n = read();
rep(i, 1, n) head[i] = -1;
Rep(i, 1, n)
{
int u = read(), v = read();
addedge(u, v), addedge(v, u);
}
dfs(1, 0); edgenum = 0;
rep(i, 1, n) head[i] = -1;
int q = read();
while (q--)
{
m = read(); num = idx = 0;
rep(i, 1, m) X[i] = Y[i] = read(), Belong[X[i]] = X[i];
Build(); up_dfs(1); down_dfs(1);
rep(i, 1, num)
travel(j, Z[i]) Solve(Z[i], edge[j].vet);
rep(i, 1, num) Ans[Belong[Z[i]]] += Rest[Z[i]];
rep(i, 1, m) printf("%d%c", Ans[Y[i]], i == m ? '\n' : ' ');
rep(i, 1, num) head[Z[i]] = -1, Belong[Z[i]] = Ans[Z[i]] = Rest[Z[i]] = 0;
}
}
文章目录
  1. 1. Description
  2. 2. Solution
  3. 3. Notice
  4. 4. Code