[HNOI 2015]接水果

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。

题解

(部分内容来自thy_asdf

我们考虑如果这个题不出在树上,而在序列上,很容易想到用$cdq$来解决。

我们想办法将树拍成一条链,通常办法是$dfs$序(其实树剖的实质也是$dfs$序),再试图找到他们之间的$dfs$序关系。

对于一条路径的子路径,在有根树上只有两种情况。我们分别考虑两种情况(记号说明:$dfn_u$表示$u$的$dfs$序,$last_u$表示以$u$为根的子树中$dfs$序最大的值):

1. 子路径经过整条路径的$lca$:

如上图所示,假设子路径$u<->v$在路径$a<->b$上。显然$a,b$分别在以$u,v$为根的子树中。

不妨设$dfn_u<=dfn_v$,$dfn_a<=dfn_b$,由$dfs$序的性质,显然存在不等式:$dfn_u<=dfn_a<=last_u$,$dfn_v<=dfn_b<=last_v$。

2. 子路径不经过整条路径的$lca$:

我们记节点$u$在路径$u<->v$上的儿子是$w$。

同样的,容易发现,路径$a<->b$若包含$u<->v$肯定需要$a$或$b$其中一个是在以$v$为根的子树中。不妨假设这个点是$a$。

那么$b$应满足:不在以$w$为根的子树中即可。

显然就有$dfn_v<=dfn_a<=last_v$,$1<=dfn_b<=dfn_w-1 \cup last_w+1<=dfn_b<=n$。

那么现在题目就转化成了不等式之间的关系,考虑$cdq$,我们需要解决的问题就是一个实数对$(dfn_a,dfn_b)$满足不等式组的个数。

继续转化,将需要同时满足的两个不等式抽象成二位空间内的一个矩形,只要点$(dfn_a,dfn_b)$在某个矩形内,就能满足这个不等式组。

现在,整个题目就是覆盖一个点的矩形中权值第$k$小的权值是多少。

将矩形按权值从小到大排序,用扫描线的思想,树状数组区间修改即可。

  1 //It is made by Awson on 2017.12.30
  2 #include <map>
  3 #include <set>
  4 #include <cmath>
  5 #include <ctime>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <string>
 11 #include <cstdlib>
 12 #include <cstring>
 13 #include <iostream>
 14 #include <algorithm>
 15 #define LL long long
 16 #define LD long double
 17 #define Max(a, b) ((a) > (b) ? (a) : (b))
 18 #define Min(a, b) ((a) < (b) ? (a) : (b))
 19 #define lowbit(x) ((x)&(-(x)))
 20 using namespace std;
 21 const int N = 80000;
 22 
 23 int n, p, q, ans[N+5];
 24 int st[N+5], ed[N+5];
 25 namespace LCA {
 26     struct tt {
 27     int to, next;
 28     }edge[(N<<1)+5];
 29     int path[N+5], tot, u, v, dfn;
 30     int top[N+5], size[N+5], son[N+5], fa[N+5], dep[N+5];
 31     void add(int u, int v) {
 32     edge[++tot].to = v;
 33     edge[tot].next = path[u];
 34     path[u] = tot;
 35     }
 36     void dfs1(int u, int father, int depth) {
 37     fa[u] = father, size[u] = 1, dep[u] = depth;
 38     for (int i = path[u]; i; i = edge[i].next)
 39         if (edge[i].to != father) {
 40         dfs1(edge[i].to, u, depth+1);
 41         size[u] += size[edge[i].to];
 42         if (size[edge[i].to] >= size[son[u]]) son[u] = edge[i].to;
 43         }
 44     }
 45     void dfs2(int u, int tp) {
 46     top[u] = tp; st[u] = ++dfn;
 47     if (son[u]) dfs2(son[u], tp);
 48     for (int i = path[u]; i; i = edge[i].next)
 49         if (edge[i].to != fa[u] && edge[i].to != son[u])
 50         dfs2(edge[i].to, edge[i].to);
 51     ed[u] = dfn;
 52     }
 53     int get_son(int u, int v) {
 54     int last = 0;
 55     while (top[u] != top[v]) {
 56         last = top[v];
 57         v = fa[last];
 58     }
 59     return u == v ? last : son[u];
 60     }
 61     int query(int u, int v) {
 62     while (top[u] != top[v]) {
 63         if (dep[top[u]] < dep[top[v]]) swap(u, v);
 64         u = fa[top[u]];
 65     }
 66     return dep[u] < dep[v] ? u : v;
 67     }
 68     void main() {
 69     for (int i = 1; i < n; i++) {
 70         scanf("%d%d", &u, &v);
 71         add(u, v), add(v, u);
 72     }
 73     dfs1(1, 0, 1); dfs2(1, 1);
 74     }
 75 }
 76 namespace CDQ {
 77     struct tt {
 78     int x1, x2, y1, y2, k;
 79     tt() {
 80     }
 81     tt(int _x1, int _x2, int _y1, int _y2, int _k) {
 82         x1 = _x1, y1 = _y1, x2 = _x2, y2 = _y2, k = _k;
 83     }
 84     bool operator < (const tt &b) const {
 85         return k < b.k;
 86     }
 87     }opt[N+5];
 88     struct ss {
 89     int x, y, k, id;
 90     ss() {
 91     }
 92     ss(int _x, int _y, int _k, int _id) {
 93         x = _x, y = _y, k = _k, id = _id;
 94     }
 95     bool operator < (const ss &b) const {
 96         return x < b.x;
 97     }
 98     }query[N+5], qu1[N+5], qu2[N+5];
 99     int u, v, k, P;
100     struct ttt {
101     int x, y, val;
102     ttt() {
103     }
104     ttt(int _x, int _y, int _val) {
105         x = _x, y = _y, val = _val;
106     }
107     bool operator < (const ttt &b) const {
108         return x < b.x;
109     }
110     }doit[(N<<1)+5];
111     struct bit_tree {
112     int c[N+5];
113     void add(int x, int val) {
114         for (; x <= n; x += lowbit(x)) c[x] += val;
115     }
116     int count(int x) {
117         int ans = 0;
118         for (; x; x -= lowbit(x)) ans += c[x];
119         return ans;
120     }
121     }T;
122     void solve(int ql, int qr, int pl, int pr) {
123      if (pl == pr) {
124         for (int i = ql; i <= qr; i++) ans[query[i].id] = opt[pl].k;
125         return;
126     }
127     int mid = (pl+pr)>>1, cnt = 0, pos = 0, q1 = 0, q2 = 0;
128     for (int i = pl; i <= mid; i++) {
129         doit[++cnt] = ttt(opt[i].x1, opt[i].y1, 1);
130         doit[++cnt] = ttt(opt[i].x1, opt[i].y2+1, -1);
131         doit[++cnt] = ttt(opt[i].x2+1, opt[i].y1, -1);
132         doit[++cnt] = ttt(opt[i].x2+1, opt[i].y2+1, 1);
133     }
134     sort(doit+1, doit+1+cnt);
135     for (int i = ql; i <= qr; i++) {
136         while (pos < cnt && doit[pos+1].x <= query[i].x) pos++, T.add(doit[pos].y, doit[pos].val);
137         int tmp = T.count(query[i].y);
138          if (query[i].k <= tmp) qu1[++q1] = query[i];
139         else query[i].k -= tmp, qu2[++q2] = query[i];
140     }
141     while (pos < cnt) pos++, T.add(doit[pos].y, doit[pos].val);
142     for (int i = 1; i <= q1; i++) query[i+ql-1] = qu1[i];
143     for (int i = 1; i <= q2; i++) query[i+q1+ql-1] = qu2[i];
144     if (q1) solve(ql, ql+q1-1, pl, mid);
145     if (q2) solve(ql+q1, qr, mid+1, pr);
146     }
147     void main() {
148     for (int i = 1; i <= p; i++) {
149         scanf("%d%d%d", &u, &v, &k);
150         if (st[u] > st[v]) swap(u, v);
151         int w = LCA::query(u, v);
152         if (u == w) {
153         w = LCA::get_son(u, v);
154         if (st[w] > 1) opt[++P] = tt(1, st[w]-1, st[v], ed[v], k);
155         if (ed[w] < n) opt[++P] = tt(st[v], ed[v], ed[w]+1, n, k);
156         }else opt[++P] = tt(st[u], ed[u], st[v], ed[v], k);
157     }
158     p = P;
159     for (int i = 1; i <= q; i++) {
160         scanf("%d%d%d", &u, &v, &k);
161         if (st[u] > st[v]) swap(u, v);
162         query[i] = ss(st[u], st[v], k, i);
163     }
164     sort(opt+1, opt+1+p); sort(query+1, query+1+q);
165         solve(1, q, 1, p);
166     }
167 }
168 
169 void work() {
170     scanf("%d%d%d", &n, &p, &q);
171     LCA::main();
172     CDQ::main();
173     for (int i = 1; i <= q; i++) printf("%d\n", ans[i]);
174 }
175 int main() {
176     work();
177     return 0;
178 }

 

posted @ 2017-12-30 16:55  NaVi_Awson  阅读(286)  评论(0编辑  收藏  举报