【HNOI2015】接水果

题面

题解

这道题要求关于第k大的东西,所以可以想到用主席树或整体二分

我们可以发现,这道题主要的难点就是路径之间的包含关系,那么我们分情况讨论:

1. LCA不是两个端点

令这个盘子的两个端点为$a,b$

如果被一个水果完全覆盖,

那么,这个水果的两端分别在$a,b$的子树中

设$pos[a]$是$a$的$dfs$序,$end_pos[a]$是子树中最大的$pos$,水果两端分别为$c, d$

$$
pos[a] \leq pos[c] \leq end_pos[a] \
pos[b] \leq pos[d] \leq end_pos[b]
$$

2. LCA是其中一个端点

令$a=LCA(a,b)$

那么,一个点还是在$b$的子树内

另一个点在这条链的子树外

设$a,b$链上的$a$的儿子为$s$

那么,水果的一个点一定不在$s$的子树内

即:

$$
pos[b] \leq pos[c] \leq end_pos[b] \
pos[d] < pos[s] \; || \; end_pos[s] < pos[d]
$$

我们将盘子的$pos[a],pos[b],end_pos[a],end_pos[b]$看成两个点

组成了一个矩形

所以,一个盘子如果被水果所完全覆盖

那么,也就是水果组成的点被盘子组成的矩形所包含

所以整体二分+扫描线求解即可

代码

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<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define clear(x, y) memset(x, y, sizeof(x));
#define for_edge(i, x) for(RG int i = head[x]; i; i = e[i].next)
#define OPERATOR(Name, key, opt) inline bool operator opt (const Name &a, const Name &b) { return a.key opt b.key; }

inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
}

const int maxn(50010);
struct edge { int next, to; } e[maxn << 1];
int head[maxn], e_num, n, P, Q, fa[20][maxn], dep[maxn], pos[maxn], end_pos[maxn], cnt, q_cnt;
inline void add_edge(int from, int to) { e[++e_num] = (edge) {head[from], to}; head[from] = e_num; }

struct Matrix { int x1, y1, x2, y2, k; } t[maxn << 2];
struct Node { int x, y, k, id; } q[maxn], pl[maxn], pr[maxn];
struct InNode { int l, r, x, val; } L[maxn];
OPERATOR(Matrix, k, <); OPERATOR(Node, x, <); OPERATOR(InNode, x, <);

void dfs(int x)
{
pos[x] = ++cnt;
for(RG int i = 1; i <= 15; i++) fa[i][x] = fa[i - 1][fa[i - 1][x]];
for_edge(i, x)
{
int to = e[i].to; if(to == fa[0][x]) continue;
fa[0][to] = x; dep[to] = dep[x] + 1; dfs(to);
}
end_pos[x] = cnt;
}

template<int T>
inline int LCA(int a, int b)
{
if(dep[a] < dep[b]) std::swap(a, b);
for(RG int i = 15; ~i; i--)
if(dep[fa[i][a]] > dep[b]) a = fa[i][a];
if(fa[0][a] == b) return T ? a : b;
a = fa[0][a];
for(RG int i = 15; ~i; i--)
if(fa[i][a] != fa[i][b]) a = fa[i][a], b = fa[i][b];
return T ? a : fa[0][a];
}

int c[maxn], ans[maxn];
inline void update(int x, int v) { while(x <= n) c[x] += v, x += x & -x; }
inline int query(int x) { int Ans = 0; while(x) Ans += c[x], x -= x & -x; return Ans; }
void Div(int l, int r, int ql, int qr)
{
if(ql > qr) return;
if(l == r) { for(RG int i = ql; i <= qr; i++) ans[q[i].id] = t[l].k; return; }

int mid = (l + r) >> 1, tl = 0, tr = 0, cntL = 0, p = 1;
for(RG int i = l; i <= mid; i++)
L[++cntL] = (InNode) {t[i].y1, t[i].y2, t[i].x1, 1},
L[++cntL] = (InNode) {t[i].y1, t[i].y2, t[i].x2 + 1, -1};
std::sort(L + 1, L + cntL + 1);

for(RG int i = ql; i <= qr; i++)
{
while(p <= cntL && L[p].x <= q[i].x) update(L[p].l, L[p].val), update(L[p].r + 1, -L[p].val), ++p;
int sum = query(q[i].y);
if(q[i].k <= sum) pl[++tl] = q[i];
else q[i].k -= sum, pr[++tr] = q[i];
}

for(RG int i = 1; i < p; i++) update(L[i].l, -L[i].val), update(L[i].r + 1, L[i].val);
for(RG int i = 1; i <= tl; i++) q[ql + i - 1] = pl[i];
for(RG int i = 1; i <= tr; i++) q[ql + tl + i - 1] = pr[i];

Div(l, mid, ql, ql + tl - 1);
Div(mid + 1, r, ql + tl, qr);
}

int main()
{
n = read(); P = read(); Q = read();
for(RG int i = 1, a, b; i < n; i++) a = read(), b = read(), add_edge(a, b), add_edge(b, a);
dep[1] = 1; dfs(1);
for(RG int i = 1, a, b, k; i <= P; i++)
{
a = read(); b = read(); k = read();
if(pos[a] > pos[b]) std::swap(a, b);
int lca = LCA<0>(a, b);
if(a != lca) t[++q_cnt] = (Matrix) {pos[a], pos[b], end_pos[a], end_pos[b], k};
else
{
int Lca = LCA<1>(a, b);
if(pos[Lca] != 1) t[++q_cnt] = (Matrix) {1, pos[b], pos[Lca] - 1, end_pos[b], k};
if(end_pos[Lca] != n) t[++q_cnt] = (Matrix) {pos[b], end_pos[Lca] + 1, end_pos[b], n, k};
}
}

for(RG int i = 1, a, b, k; i <= Q; i++)
{
a = read(); b = read(); k = read();
if(pos[a] > pos[b]) std::swap(a, b);
q[i] = (Node) {pos[a], pos[b], k, i};
}

std::sort(t + 1, t + q_cnt + 1);
std::sort(q + 1, q + Q + 1);
clear(c, 0);
Div(1, q_cnt, 1, Q);

for(RG int i = 1; i <= Q; i++) printf("%d\n", ans[i]);
return 0;
}
Your browser is out-of-date!

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

×