4009: [HNOI2015]接水果
Time Limit: 60 Sec Memory Limit: 512 MB
Submit: 633 Solved: 299
[Submit][Status][Discuss]
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。
Source
http://blog.csdn.net/thy_asdf/article/details/50363672
前面的部分说的很详细了。但是写的时候要注意几点:
1. 判断lca类型的时候u和v比较的是dfn大小,不是dep大小
2.水果读入的时候如果dfn[x1] > dfn[y1] swap(x1, y1)
3.整体二分里排序注意插入删除和水果的顺序
#include<bits/stdc++.h> using namespace std; const int N = 100010; int n, p, m, cnt, tot = 1, Time; struct E { int nxt, to; } e[N << 1]; struct P { int x1, y1, x2, y2, w, id, k, type; P(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, int w = 0, int id = 0, int k = 0, int type = 0) : x1(x1), y1(y1), x2(x2), y2(y2), w(w), id(id), k(k), type(type) {} } event[N], q[N]; struct BIT { int tree[N]; int lowbit(int x) {return x&(-x);} void update(int l, int r, int v) { for(int i = l; i <= n; i += lowbit(i)) tree[i] += v; for(int i = r + 1; i <= n; i += lowbit(i)) tree[i] -= v; } int query(int pos) {int ret = 0; for(int i = pos; i; i -= lowbit(i)) ret += tree[i]; return ret;} } t; vector<P> c, lp, rp; int head[N], ans[N], low[N], dfn[N] ,fa[23][N], dep[N]; void link(int u, int v) { e[++tot].nxt = head[u]; head[u] = tot; e[tot].to = v; } bool cp(P i, P j) {return i.w < j.w;} bool cp1(P i, P j) {return i.x1 == j.x1 ? i.type < j.type : i.x1 < j.x1;} void dfs(int u, int last) { dfn[u] = ++Time; for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last) { fa[0][e[i].to] = u; dep[e[i].to] = dep[u] + 1; dfs(e[i].to, u); } low[u] = Time; } int lca(int u, int v) { if(dep[u] < dep[v]) swap(u, v); for(int i = 22; i >= 0; --i) if((dep[u] - dep[v]) & (1 << i)) u = fa[i][u]; if(u == v) return u; for(int i = 22; i >= 0; --i) if(fa[i][u] != fa[i][v]) { u = fa[i][u]; v = fa[i][v]; } return fa[0][u]; } int jump(int u, int h) { for(int i = 22; i >= 0; --i) if(h & (1 << i)) u = fa[i][u]; return u; } void solve(int l, int r, int lb, int rb) { if(l > r) return; if(lb == rb) { for(int i = l; i <= r; ++i) ans[q[i].id] = event[lb].w; return; } int mb = (lb + rb) >> 1; c.clear(); lp.clear(); rp.clear(); for(int i = lb; i <= mb; ++i) {//盘子 P x = event[i]; // printf("x1=%d x2=%d\n", x.x1, x.x2); x.w = 1; x.type = 0; c.push_back(x); x.type = 2; x.w = -1; x.x1 = event[i].x2; c.push_back(x); } for(int i = l; i <= r; ++i) {//水果 c.push_back(q[i]); } sort(c.begin(), c.end(), cp1); for(int i = 0; i < c.size(); ++i) { if(c[i].type != 1) { // printf("x=%d y1=%d y2=%d\n", c[i].x1, c[i].y1, c[i].y2); t.update(c[i].y1, c[i].y2, c[i].w); } else { int sum = t.query(c[i].y1); // printf("sum=%d k=%d\n", sum, c[i].k); if(sum >= c[i].k) lp.push_back(c[i]); else {c[i].k -= sum; rp.push_back(c[i]);} } } for(int i = 0; i < c.size(); ++i) if(c[i].type != 1) t.update(c[i].y1, c[i].y2, -c[i].w); for(int i = 0; i < lp.size(); ++i) q[l + i] = lp[i]; for(int i = 0; i < rp.size(); ++i) q[l + lp.size() + i] = rp[i]; int mid = l + lp.size() - 1; solve(l, mid, lb, mb); solve(mid + 1, r, mb + 1, rb); } int main() { freopen("fruit_hnoi2015.in", "r", stdin); freopen("fruit_hnoi2015.out", "w", stdout); scanf("%d%d%d",&n,&p,&m); for(int i = 1; i < n; ++i) { int u, v; scanf("%d%d",&u,&v); link(u, v); link(v, u); } memset(fa, -1, sizeof(fa)); dfs(1, 0); for(int i = 1; i <= 22; ++i) for(int j = 1; j <= n; ++j) if(fa[i-1][j] != -1) fa[i][j] = fa[i-1][fa[i-1][j]]; for(int i = 1; i <= p; ++i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); int x = lca(u, v); if(dfn[u] > dfn[v]) swap(u, v); if(u != x) { event[++cnt].x1 = dfn[u]; event[cnt].y1 = dfn[v]; event[cnt].x2 = low[u]; event[cnt].y2 = low[v]; event[cnt].w = w; } else { int t = jump(v, dep[v] - dep[u] - 1); event[++cnt].x1 = 1; event[cnt].y1 = dfn[v]; event[cnt].x2 = dfn[t] - 1; event[cnt].y2 = low[v]; event[cnt].w = w; if(low[t] < n) { event[++cnt].x1 = dfn[v]; event[cnt].y1 = low[t] + 1; event[cnt].x2 = low[v]; event[cnt].y2 = n; event[cnt].w = w; } } } for(int i = 1; i <= m; ++i) { int u, v; scanf("%d%d%d", &u, &v, &q[i].k); if(dfn[u] > dfn[v]) swap(u, v); q[i].x1 = dfn[u]; q[i].y1 = dfn[v]; q[i].id = i; q[i].type = 1; } sort(event + 1, event + cnt + 1, cp); solve(1, m, 1, cnt); for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]); fclose(stdin); fclose(stdout); return 0; }