SP1487 PT07J - Query on a tree III 题解

· · 题解

谁告诉你这题不能莫队了。

考虑到如果是一条树上路径的话,那么可以用欧拉序,因为树上路径在欧拉序上是连续的。

但是子树呢?

考虑一颗子树在 dfs 序上是连续的,所以 dfs 序上莫队是可行的。

处理区间第 k 大,考虑值域分块。

所以查询时,先跳 $G_i$ 找出第 $k$ 大的块,然后块内暴力,复杂度 $\mathcal{O(n\sqrt n})$。 跑的飞快,直接最优解。 ```cpp #include<bits/stdc++.h> using namespace std; const int N = 100010; int cnt[N], a[N], n, q, k, ans[N]; struct Query {int id, l, r, k;} Q[N]; int now, in[N]; void add(int x) {cnt[x]++; if(cnt[x] == 1) now++;} void del(int x) {cnt[x]--; if(!cnt[x]) now--;} bool cmp(Query a, Query b) {return in[a.l] != in[b.l] ? in[a.l] < in[b.l] : a.r < b.r;} vector<int> e[N]; int sz[N], D[N], d[N], tot; void dfs(int u, int fa) { sz[u] = 1; D[++tot] = u; d[u] = tot; for(int v: e[u]) { if(v == fa) continue; dfs(v, u); sz[u] += sz[v]; } } int g[N], G[N], base, L[N], R[N], B, to[N]; void Add(int x) {g[x]++; G[in[x]]++;} void Del(int x) {g[x]--; G[in[x]]--;} int find(int k) { int sum = 0, pos = -1; for(int i = 1; i <= B; i++) {sum += G[i]; if(sum >= k) {pos = i; break;} } // cout << "pos = " << pos << ' ' << G[pos] << '\n'; sum -= G[pos]; for(int i = L[pos]; i <= R[pos]; i++) {sum += g[i]; if(sum >= k) return i;} return 114514; } int b[N]; int main() { ios::sync_with_stdio(0); cin >> n; for(int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i]; sort(b + 1, b + 1 + n); for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b; // for(int i = 1; i <= n; i++) cout << a[i] << ' '; cout << '\n'; for(int i = 1; i <= n; i++) to[a[i]] = i; for(int i = 1; i < n; i++) { int a, b; cin >> a >> b; e[a].push_back(b); e[b].push_back(a); } dfs(1, 0); cin >> q; base = sqrt(n); for(int i = 1; i <= n; i++) in[i] = (i + base - 1) / base; int x; B = in[n]; for(int i = 1; i <= B; i++) L[i] = (i - 1) * base + 1, R[i] = min(i * base, n); for(int i = 0; i < q; i++) cin >> x >> Q[i].k, Q[i].l = d[x], Q[i].r = d[x] + sz[x] - 1, Q[i].id = i; int l = 1, r = 0; sort(Q, Q + q, cmp); // for(int i = 0; i < q; i++) cout << Q[i].l << ' ' << Q[i].r << '\n'; // for(int i = 1; i <= n; i++) cout << D[i] << ' '; for(int i = 0; i < q; i++) { while(r < Q[i].r) Add(a[D[++r]]); while(l > Q[i].l) Add(a[D[--l]]); while(r > Q[i].r) Del(a[D[r--]]); while(l < Q[i].l) Del(a[D[l++]]); // cout << "l = " << l << " r = " << r << '\n'; // cout << "find = " << find(Q[i].k) << '\n'; ans[Q[i].id] = to[find(Q[i].k)]; } for(int i = 0; i < q; i++) cout << ans[i] << '\n'; return 0; } ```