[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 }?
轉載于:https://www.cnblogs.com/NaVi-Awson/p/8150418.html
總結
以上是生活随笔為你收集整理的[HNOI 2015]接水果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝桥杯练习题十六进制转十进制
- 下一篇: 行车记录仪接降压线对电瓶有影响吗