主席树(应用)

主席树(应用)


【树上主席树】:

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+TreeyTreeLCA(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;
}

你可能感兴趣的:(ACM——数据结构)