Description
风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。
由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更
加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1
给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条
路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个
盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),
权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第
i 个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水
果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如
图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与
从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择
能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数
的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水
果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
Input
第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。
接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点
按1到 n标号。 接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其
中0≤c≤10^9,a不等于b。
接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,
第k 小一定存在。
Output
对于每个果子,输出一行表示选择的盘子的权值。
Sample Input
10 10 10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
3 2 217394434
10 7 13022269
6 7 283254485
6 8 333042360
4 6 442139372
8 3 225045590
10 4 922205209
10 8 808296330
9 2 486331361
4 9 551176338
1 8 5
3 8 3
3 8 4
1 8 3
4 8 1
2 3 1
2 3 1
2 3 1
2 4 1
1 4 1
Sample Output
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
HINT
N,P,Q<=40000。
Solution
下面把树选一个点为根进行一遍 dfs ,
dfnu
d
f
n
u
为
u
u
的 dfs 序, 为
u
u
的子树大小。
考虑如何把「 是
x−>y
x
−
>
y
的子路径」这一条件转化。
如果
a
a
和 在树上没有祖先关系,那么设
dfna<dfnb
d
f
n
a
<
d
f
n
b
且
dfnx<dfny
d
f
n
x
<
d
f
n
y
,原条件等价于:
a
a
的子树内有 ,且
b
b
的子树内有 。即:
再考虑如果 a a 是 的祖先,这时候可以找出一个点 u u ,它满足:
的父亲是 a a 且 在 a−>b a − > b 的路径上。
那么这样条件可以转化为:
(1) b b 的子树内有 且 u u 的子树内没有 。
(2) b b 的子树内有 且 u u 的子树内没有 。
(满足上面两个条件 之一即可)
也就是说:
于是问题转化为,有一些带权值的矩形,每次询问包含一个点 (x,y) ( x , y ) 的所有矩形中,权值第 k k 小的矩形。
直接做是不可做的,因此考虑离线后使用扫描线解决,把一个矩形拆成进入扫描线和离开扫描线两次操作。
这样就变成了另一个问题:一个序列,每次在区间 内的每个位置插入或删除一个数 x x ,或者询问一个位置 上第 k k 小的数。
可以使用线段树套线段树维护这个序列,第一维值域,第二维位置。对于空间问题可以使用动态开点。
修改时,从外层线段树的根一直走到 表示的叶子节点,把每个节点内部线段树的区间 [l,r] [ l , r ] 加(减) 1 1 <script type="math/tex" id="MathJax-Element-10567">1</script> 。
询问时,在外层线段树上二分可以得到答案。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define p2 p << 1
#define p3 p << 1 | 1
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v; e; e = nxt[e])
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 4e4 + 5, M = N << 1, R = M << 1, Z = R << 1, L = 3e7 + 5, LogN = 18;
int n, p, q, m, ecnt, nxt[M], adj[N], go[M], dfn[N], sze[N],
times, fa[N][LogN], dep[N], tm, qp[Z], rt[R], QAQ, ans[N];
struct cyx {int i, l, r, c, op;} orz[Z];
struct pyz {int u, v, c, id;} otz[N];
struct mx {int lc, rc, add; void init() {lc = rc = add;}} T[L];
void modify(int l, int r, int s, int e, int v, int &p) {
if (!p) T[p = ++QAQ].init(); if (l == s && r == e)
return (void) (T[p].add += v); int mid = l + r >> 1; if (T[p].add) {
if (!T[p].lc) T[T[p].lc = ++QAQ].init();
if (!T[p].rc) T[T[p].rc = ++QAQ].init();
T[T[p].lc].add += T[p].add; T[T[p].rc].add += T[p].add; T[p].add = 0;
}
if (e <= mid) modify(l, mid, s, e, v, T[p].lc);
else if (s >= mid + 1) modify(mid + 1, r, s, e, v, T[p].rc);
else modify(l, mid, s, mid, v, T[p].lc),
modify(mid + 1, r, mid + 1, e, v, T[p].rc);
}
void change(int l, int r, int pos, int x, int y, int d, int p) {
modify(1, n, x, y, d, rt[p]); if (l == r) return; int mid = l + r >> 1;
if (pos <= mid) change(l, mid, pos, x, y, d, p2);
else change(mid + 1, r, pos, x, y, d, p3);
}
int query(int l, int r, int pos, int p) {
if (!p) return 0; if (l == r) return T[p].add; int mid = l + r >> 1;
return T[p].add + (pos <= mid ? query(l, mid, pos, T[p].lc)
: query(mid + 1, r, pos, T[p].rc));
}
int ask(int l, int r, int pos, int k, int p) {
if (l == r) return l; int mid = l + r >> 1, delta = query(1, n, pos, rt[p2]);
if (k <= delta) return ask(l, mid, pos, k, p2);
else return ask(mid + 1, r, pos, k - delta, p3);
}
inline bool cyxdalao(const cyx &a, const cyx &b) {return a.i < b.i;}
inline bool pyzdalao(const pyz &a, const pyz &b) {return a.v < b.v;}
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}
void dfs(int u, int fu) {
int i; dfn[u] = ++times; dep[u] = dep[fa[u][0] = fu] + (sze[u] = 1);
For (i, 0, 15) fa[u][i + 1] = fa[fa[u][i]][i];
Edge(u) if ((v = go[e]) != fu) dfs(v, u), sze[u] += sze[v];
}
int jump(int u, int x) {
int i; For (i, 0, 16) if ((x >> i) & 1) u = fa[u][i]; return u;
}
int main() {
int i, x, y, z; n = read(); p = read(); q = read();
For (i, 1, n - 1) x = read(), y = read(), add_edge(x, y); dfs(1, 0);
For (i, 1, p) {
x = read(); y = read(); z = read(); if (dfn[x] > dfn[y]) swap(x, y);
if (dfn[x] <= dfn[y] && dfn[y] <= dfn[x] + sze[x] - 1) {
int o = jump(y, dep[y] - dep[x] - 1), xl = dfn[o],
xr = dfn[o] + sze[o] - 1; if (xl > 1) {
orz[++m] = (cyx) {dfn[y], 1, xl - 1, z, 1};
orz[++m] = (cyx) {dfn[y] + sze[y], 1, xl - 1, z, -1};
}
if (xr < n) {
orz[++m] = (cyx) {dfn[y], xr + 1, n, z, 1};
orz[++m] = (cyx) {dfn[y] + sze[y], xr + 1, n, z, -1};
}
orz[++m] = (cyx) {1, dfn[y], dfn[y] + sze[y] - 1, z, 1};
orz[++m] = (cyx) {xl, dfn[y], dfn[y] + sze[y] - 1, z, -1};
orz[++m] = (cyx) {xr + 1, dfn[y], dfn[y] + sze[y] - 1, z, 1};
orz[++m] = (cyx) {n + 1, dfn[y], dfn[y] + sze[y] - 1, z, -1};
}
else {
int xl = dfn[x], xr = dfn[x] + sze[x] - 1;
orz[++m] = (cyx) {dfn[y], xl, xr, z, 1};
orz[++m] = (cyx) {dfn[y] + sze[y], xl, xr, z, -1};
}
}
For (i, 1, q) {
x = read(); y = read(); z = read(); if (dfn[x] > dfn[y]) swap(x, y);
otz[i] = (pyz) {dfn[x], dfn[y], z, i};
}
sort(orz + 1, orz + m + 1, cyxdalao); sort(otz + 1, otz + q + 1, pyzdalao);
For (i, 1, m) qp[i] = orz[i].c; sort(qp + 1, qp + m + 1);
tm = unique(qp + 1, qp + m + 1) - qp - 1; For (i, 1, m)
orz[i].c = lower_bound(qp + 1, qp + tm + 1, orz[i].c) - qp;
int j = 1; For (i, 1, q) {
while (j <= m && orz[j].i <= otz[i].v)
change(1, tm, orz[j].c, orz[j].l, orz[j].r, orz[j].op, 1), j++;
ans[otz[i].id] = ask(1, tm, otz[i].u, otz[i].c, 1);
}
For (i, 1, q) printf("%d\n", qp[ans[i]]); return 0;
}