[BZOJ 1803] Query on a tree III
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1803
[算法]
首先 , 一棵子树的DFS序必然为连续的一段
通过这个性质 , 我们将一个树上的问题转化为了一个序列上的问题
可持久化线段树可以解决该问题 , 不再赘述
时间复杂度 : O(MlogN)
[代码]
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 10; struct edge { int to , nxt; } e[MAXN << 2]; int tot , n , m , timer , idx; int root[MAXN] , dfn[MAXN] , size[MAXN] , head[MAXN] , a[MAXN] , order[MAXN] , tmp[MAXN] , loc[MAXN] , lson[MAXN * 40] , rson[MAXN * 40] , sum[MAXN * 40]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int x , int y) { ++tot; e[tot] = (edge){y , head[x]}; head[x] = tot; } inline bool cmp(int x , int y) { return dfn[x] < dfn[y]; } inline void dfs(int u , int fa) { dfn[u] = ++timer; size[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa) continue; dfs(v , u); size[u] += size[v]; } } inline void build(int &k , int l , int r) { k = ++idx; if (l == r) return; int mid = (l + r) >> 1; build(lson[k] , l , mid); build(rson[k] , mid + 1 , r); } inline void modify(int &k , int old , int l , int r , int pos , int value) { k = ++idx; lson[k] = lson[old] , rson[k] = rson[old]; sum[k] = sum[old] + value; if (l == r) return; int mid = (l + r) >> 1; if (mid >= pos) modify(lson[k] , lson[k] , l , mid , pos , value); else modify(rson[k] , rson[k] , mid + 1 , r , pos , value); } inline int query(int rt1 , int rt2 , int l , int r , int k) { if (l == r) return l; int mid = (l + r) >> 1; if (sum[lson[rt1]] - sum[lson[rt2]] >= k) return query(lson[rt1] , lson[rt2] , l , mid , k); else return query(rson[rt1] , rson[rt2] , mid + 1 , r , k - (sum[lson[rt1]] - sum[lson[rt2]])); } int main() { read(n); for (int i = 1; i <= n; i++) { read(a[i]); tmp[i] = a[i]; } sort(tmp + 1 , tmp + n + 1); for (int i = 1; i <= n; i++) { int l = 1 , r = n , pos; while (l <= r) { int mid = (l + r) >> 1; if (tmp[mid] >= a[i]) { pos = mid; r = mid - 1; } else l = mid + 1; } a[i] = pos; loc[pos] = i; } for (int i = 1; i < n; i++) { int x , y; read(x); read(y); addedge(x , y); addedge(y , x); } dfs(1 , 0); for (int i = 1; i <= n; i++) order[i] = i; sort(order + 1 , order + n + 1 , cmp); build(root[0] , 1 , n); for (int i = 1; i <= n; i++) modify(root[i] , root[i - 1] , 1 , n , a[order[i]] , 1); read(m); while (m--) { int u , k; read(u); read(k); printf("%d\n" , loc[query(root[dfn[u] + size[u] - 1] , root[dfn[u] - 1] , 1 , n , k)]); } return 0; }