【树上主席树】:
You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.
We will ask you to perform the following operation:
u v k : ask for the kth minimum weight on the path from node u to node v
Input
In the first line there are two integers N and M. (N, M <= 100000)
In the second line there are N integers. The ith integer denotes the weight of the ith node.
In the next N-1 lines, each line contains two integers u v, which describes an edge (u, v).
In the next M lines, each line contains three integers u v k, which means an operation asking for the kth minimum weight on the path from node u to node v.
Output
For each operation, print its result.
Example Input:
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2
Example Output:
2
8
9
105
7
题目分析:
按照树的DFS顺序建立主席树,设x,y点对应的主席树为 T r e e x , T r e e y Tree_x,Tree_y Treex,Treey,由于主席数搭载是按照树的DFS顺序,为了获取x到y上的结点信息我们可以这样做: T r e e x + T r e e y − T r e e L C A ( x , y ) − T r e e f a [ L C A ( x , y ) ] Tree_x+Tree_y-Tree_{LCA(x,y)}-Tree_{fa[LCA(x,y)]} Treex+Treey−TreeLCA(x,y)−Treefa[LCA(x,y)]。
所以这题为LCA+主席树。
代码:
#include
#include
#include
#include
#define mp make_pair
#define mid ( l + r ) / 2
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 10;
int n, m, w[N], cnt, last[N], b[N],cntp;
int chm[N], Num[32 * N], Lson[32 * N], Rson[32 * N];
int dep[N], f[N][22], x, y, len, k;
struct node
{
int to, nxt;
}e[2 * N];
void Add(int x, int y)
{
++cnt;
e[cnt].nxt = last[x];
last[x] = cnt;
e[cnt].to = y;
}
void LCA_dfs(int now, int fa)
{
dep[now] = dep[fa] + 1;
for(int i = 0; i <= 20; ++i)
f[now][i + 1] = f[f[now][i]][i];
for(int i = last[now]; i; i = e[i].nxt)
{
if(e[i].to == fa) continue;
f[e[i].to][0] = now;
LCA_dfs(e[i].to, now);
}
}
int LCA(int x, int y)
{
if(dep[x] < dep[y]) swap(x, y);
for(int i = 20; i >= 0; --i)
{
if(dep[f[x][i]] >= dep[y])
x = f[x][i];
if(x == y) return x;
}
for(int i = 20; i >= 0; --i)
{
if(f[x][i] != f[y][i])
{
x = f[x][i];
y = f[y][i];
}
}
return f[x][0];
}
ll Build_empty(int l, int r)
{
int rt = ++cntp;
Num[rt] = 0;
if(l < r)
{
Lson[rt] = Build_empty(l, mid);
Rson[rt] = Build_empty(mid + 1, r);
}
return rt;
}
int Update(int pre, int l, int r, int x)
{
int rt = cntp++;
Num[rt] = Num[pre] + 1;
Lson[rt] = Lson[pre];
Rson[rt] = Rson[pre];
if(l < r)
{
if(x <= mid) Lson[rt] = Update(Lson[pre], l, mid, x);
else Rson[rt] = Update(Rson[pre], mid + 1, r, x);
}
return rt;
}
void Tree_dfs(int now, int fa)
{
int pos = lower_bound(b + 1, b + len + 1, w[now]) - b;
chm[now] = Update(chm[fa],1, len, pos);
for(int i = last[now]; i; i = e[i].nxt)
{
if(e[i].to == fa) continue;
Tree_dfs(e[i].to, now);
}
}
int Query(int rt_x, int rt_y, int rt_lca, int rt_lca_fa, int l, int r, int k)
{
int x = Num[Lson[rt_x]] + Num[Lson[rt_y]] - Num[Lson[rt_lca]] -Num[Lson[rt_lca_fa]];
if(l >= r) return l;
if(k <= x) return Query(Lson[rt_x], Lson[rt_y], Lson[rt_lca], Lson[rt_lca_fa], l, mid, k);
else return Query(Rson[rt_x], Rson[rt_y], Rson[rt_lca], Rson[rt_lca_fa], mid + 1, r, k - x);
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
{
scanf("%d", w + i);
b[i] = w[i];
}
sort(b + 1, b + n + 1);
len = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n - 1; ++i)
{
scanf("%d%d", &x, &y);
Add(x, y);
Add(y, x);
}
chm[0] = Build_empty(1, len);
LCA_dfs(1, 0);
Tree_dfs(1, 0);
for(int i = 1; i <= m; ++i)
{
scanf("%d%d%d", &x, &y, &k);
int lca = LCA(x, y);
int pos = Query(chm[x], chm[y], chm[lca], chm[f[lca][0]], 1, len, k);
printf("%d\n",b[pos]);
}
return 0;
}