【2018 12月集训 Day2】小奇的危机
给定一棵树,有若干次询问,每次给定 $l,r,x$,求一个点 $y$,满足 $l \le y \le r$,且最小化 $\text{dis}(x,y)$
$n,q \le 10^5, l \le r$,任意两个点的距离不超过 $10^9$
有一个十分自然的鬼畜想法就是把每个询问 $[l,r]$,拆分成 $\log n$ 个区间放到线段树上,然后依次访问线段树的每一个区间
之后对当前区间(假设是 $[L,R]$)的所有询问点和下标在 $[L,R]$ 的点建立虚树
之后就相当于给定一棵树,有一些关键点,问所有点到所有关键点的距离最小值是多少
这个可以跑两次树上动态规划来解决掉
之后就能过了……时间复杂度 $O((n+q) \log^2 n)$
如果要求强制在线呢?其实也很简单(不知道对不对……口胡一下……)……
这回就相当于给定一棵树,树上有关键点,还有若干次询问,每次给定一个点,问这个点到树上所有关键点的最近距离
这样只需要找到这个点和树的两个交点就行了,显然要么这个点在虚树外,要么在虚树上,要么在虚树上某两个点之间
对于第一种情况,只可能是该点的子树中有虚树的根,或者该点到原树的根节点的路径上有虚树的根,要么就是该点和虚树的根节点的最近公共祖先在该点到原树的根上
对于第二种情况,直接输出预处理的答案就行了
对于第三种情况,直接查找虚树上的这两个点后更新答案就行了
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 struct FastIO { 5 static const int S = 2e7; 6 int wpos; 7 char wbuf[S]; 8 FastIO() : wpos(0) {} 9 inline int xchar() { 10 static char buf[S]; 11 static int len = 0, pos = 0; 12 if (pos == len) 13 pos = 0, len = fread(buf, 1, S, stdin); 14 if (pos == len) exit(0); 15 return buf[pos++]; 16 } 17 inline int operator () () { 18 int c = xchar(), x = 0; 19 while (c <= 32) c = xchar(); 20 for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0'; 21 return x; 22 } 23 inline void wchar(int x) { 24 if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0; 25 wbuf[wpos++] = x; 26 } 27 inline void operator () (int x) { 28 char s[24]; 29 int n = 0; 30 while (x || !n) s[n++] = '0' + x % 10, x /= 10; 31 while (n--) wchar(s[n]); 32 wchar('\n'); 33 } 34 ~FastIO() 35 { 36 if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0; 37 } 38 } io; 39 40 const int N = 100000 + 10; 41 42 int n, q; 43 44 int _head[N], _rest[N * 2], _to[N * 2], _w[N * 2]; 45 void lk(int u, int v, int w) { 46 static int tot = 0; 47 _to[++ tot] = v, _w[tot] = w, _rest[tot] = _head[u], _head[u] = tot; 48 _to[++ tot] = u, _w[tot] = w, _rest[tot] = _head[v], _head[v] = tot; 49 } 50 51 struct T { 52 int id, x; 53 }; 54 55 vector<T> que[N * 10]; 56 57 #define lc (id << 1) 58 #define rc (id << 1 | 1) 59 void poi(int id, int l, int r, int ql, int qr, T t) { 60 int mid = (l + r) >> 1; 61 if(ql <= l && r <= qr) { 62 que[id].push_back(t); 63 } else if(qr <= mid) { 64 poi(lc, l, mid, ql, qr, t); 65 } else if(ql >= mid + 1) { 66 poi(rc, mid + 1, r, ql, qr, t); 67 } else { 68 poi(lc, l, mid, ql, mid, t); 69 poi(rc, mid + 1, r, mid + 1, qr, t); 70 } 71 } 72 73 int ans[N], beg_dfn[N], end_dfn[N], clk, dep[N], len[N]; 74 int fa[N][21]; 75 76 int getlca(int u, int v) { 77 if(dep[u] < dep[v]) swap(u, v); 78 for(int i = 20 ; ~ i ; -- i) 79 if(dep[fa[u][i]] >= dep[v]) 80 u = fa[u][i]; 81 if(u == v) return u; 82 for(int i = 20 ; ~ i ; -- i) 83 if(fa[u][i] != fa[v][i]) 84 u = fa[u][i], v = fa[v][i]; 85 return fa[u][0]; 86 } 87 88 void getdfn(int u, int fa) { 89 :: fa[u][0] = fa; 90 for(int i = 1 ; i <= 20 ; ++ i) 91 :: fa[u][i] = :: fa[:: fa[u][i - 1]][i - 1]; 92 93 beg_dfn[u] = ++ clk; 94 dep[u] = dep[fa] + 1; 95 for(int i = _head[u] ; i ; i = _rest[i]) { 96 int v = _to[i], w = _w[i]; 97 if(v == fa) continue; 98 len[v] = len[u] + w; 99 getdfn(v, u); 100 } 101 end_dfn[u] = clk; 102 } 103 104 int a[N * 10], top, root, spe[N]; 105 int cmp(int x, int y) { return beg_dfn[x] < beg_dfn[y]; } 106 107 const int inf = 0x3f3f3f3f; 108 int f[N], h[N]; 109 110 int head[N], rest[N * 2], to[N * 2], w[N * 2], tot; 111 112 int thev[N], thew[N], the_top; 113 114 namespace TreeDP { 115 void dfs(int u, int fa) { 116 f[u] = inf; 117 if(spe[u]) f[u] = 0; 118 for(int i = head[u] ; i ; i = rest[i]) { 119 int v = to[i], w = :: w[i]; 120 if(v == fa) continue; 121 dfs(v, u); 122 f[u] = min(f[u], f[v] + w); 123 } 124 } 125 126 void go(int u, int fa) { 127 if(u == root) h[u] = inf; 128 if(spe[u]) h[u] = 0; 129 130 the_top = 0; 131 for(int i = head[u] ; i ; i = rest[i]) { 132 int v = to[i], w = :: w[i]; 133 if(v == fa) continue; 134 thev[++ the_top] = v; 135 thew[the_top] = w; 136 } 137 138 int themn = inf; 139 for(int i = 1 ; i <= the_top ; ++ i) { 140 int v = thev[i], w = thew[i]; 141 h[v] = h[u] + w; 142 h[v] = min(h[v], themn + w); 143 themn = min(themn, f[v] + w); 144 } 145 themn = inf; 146 for(int i = the_top ; i >= 1 ; -- i) { 147 int v = thev[i], w = thew[i]; 148 h[v] = min(h[v], themn + w); 149 themn = min(themn, f[v] + w); 150 } 151 for(int i = head[u] ; i ; i = rest[i]) { 152 int v = to[i]; 153 if(v == fa) continue; 154 go(v, u); 155 } 156 } 157 158 void sol(int root) { 159 dfs(root, 0); 160 go(root, 0); 161 } 162 } 163 164 void add(int u, int v, int w) { 165 to[++ tot] = v, :: w[tot] = w, rest[tot] = head[u], head[u] = tot; 166 to[++ tot] = u, :: w[tot] = w, rest[tot] = head[v], head[v] = tot; 167 } 168 169 int sta[N], statop; 170 171 void dfs(int id, int l, int r) { 172 int mid = (l + r) >> 1; 173 174 if(que[id].size()) { 175 top = 0; 176 for(int i = l ; i <= r ; ++ i) { 177 a[++ top] = i; 178 spe[i] = 1; 179 } 180 for(T t: que[id]) { 181 a[++ top] = t.x; 182 } 183 sort(a + 1, a + 1 + top, cmp); 184 top = unique(a + 1, a + 1 + top) - a - 1; 185 186 for(int i = top ; i >= 2 ; -- i) 187 a[++ top] = getlca(a[i], a[i - 1]); 188 sort(a + 1, a + 1 + top, cmp); 189 top = unique(a + 1, a + 1 + top) - a - 1; 190 191 tot = 0; 192 for(int i = 1 ; i <= top ; ++ i) 193 head[a[i]] = 0; 194 root = a[1]; 195 196 statop = 0; 197 for(int i = 1 ; i <= top ; ++ i) { 198 int u = a[i]; 199 while(statop && end_dfn[sta[statop]] < beg_dfn[u]) -- statop; 200 if(statop) { 201 add(sta[statop], u, len[u] - len[sta[statop]]); 202 } 203 sta[++ statop] = u; 204 } 205 206 TreeDP :: sol(root); 207 208 for(T t: que[id]) { 209 int ansid = t.id, u = t.x; 210 ans[ansid] = min(ans[ansid], min(f[u], h[u])); 211 } 212 213 for(int i = l ; i <= r ; ++ i) spe[i] = 0; 214 } 215 if(l != r) dfs(lc, l, mid), dfs(rc, mid + 1, r); 216 } 217 218 int main() { 219 n = io(); 220 for(int i = 1, u, v, w ; i < n ; ++ i) { 221 u = io(), v = io(), w = io(); 222 lk(u, v, w); 223 } 224 getdfn(1, 0); 225 q = io(); 226 227 memset(ans, 0x3f, sizeof(int) * (q + 5)); 228 229 for(int i = 1, l, r, x ; i <= q ; ++ i) { 230 l = io(), r = io(), x = io(); 231 poi(1, 1, n, l, r, (T) { i, x }); 232 } 233 234 dfs(1, 1, n); 235 for(int i = 1 ; i <= q ; ++ i) { 236 io(ans[i]); 237 } 238 }