2588: Spoj 10628. Count on a tree(树上主席树 点权的第k大)

2588: Spoj 10628. Count on a tree

题目链接

https://vjudge.net/problem/HYSBZ-2588

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 9536  Solved: 2515
[Submit][Status][Discuss]

Description

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

Input

第一行两个整数N,M。

第二行有N个整数,其中第i个整数表示点i的权值。

后面N-1行每行两个整数(x,y),表示点x到点y有一条边。

最后M行每行两个整数(u,v,k),表示一组询问。

Output

M行,表示每个询问的答案。最后一个询问不输出换行符

Sample 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
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output

2
8
9
105
7

HINT

N,M<=100000

暴力自重。。。

上一篇文章中我们写道了树上可持续化线段树,每经历一个点为该结点能达到的最大深去更新当前线段树,然后查询当前深度到线段树的最后面之和,就是当前结点所有的权值。类似差分,只需要更新一次该节点,子树结点查询一次就相当于更新了。

题意:给定一棵树,树上每个节点都有一个权值,问两点之间路径上第K大值

树上的第k大值,跟区间第k大有些不同,区间第k大每个值在前一个值的基础上新建一棵树,而树上第k大则是在父亲节点的基础上新建一棵树。查询的时候,答案就是root[v] + root[u] - root[lca(v, u)] - root[fa[lca(v,u)]]上的第k大

上面是点权的做法,边权呢就不需要- root[fa[lca(v,u)]]了。就是是root[v] + root[u] - 2*root[lca(v, u)]。边权的第k大将会在下一篇文章写出。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int inf=1e9+10;
vector<int>G[N];
int cnt;
int a[N],b[N],sz;
int ls[N*40],rs[40*N],sum[40*N],rt[N],dep[N],fa[N][30];
int n,m; 
int getid(int x)
{
	return lower_bound(b+1,b+1+sz,x)-b;
}
void up(int pre,int &o,int l,int r,int val)
{
	o=++cnt;
	ls[o]=ls[pre];
	rs[o]=rs[pre];
	sum[o]=sum[pre]+1;
	if(l==r) return ;
	int mid=l+r>>1;
	if(val<=mid) up(ls[pre],ls[o],l,mid,val);
	else up(rs[pre],rs[o],mid+1,r,val);
}
int qu(int pre,int o,int lca,int falca,int l,int r,int k)
{
	if(l==r) return l;
	int mid=l+r>>1;
	int cmp=sum[ls[pre]]+sum[ls[o]]-sum[ls[lca]]-sum[ls[falca]];
	if(cmp>=k) return qu(ls[pre],ls[o],ls[lca],ls[falca],l,mid,k);
	else return qu(rs[pre],rs[o],rs[lca],rs[falca],mid+1,r,k-cmp); 
}
void dfs(int pre,int u,int f,int d)
{
	fa[u][0]=f;
	dep[u]=d;
	up(pre,rt[u],1,sz,getid(a[u]));
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==f) continue;
		dfs(rt[u],v,u,d+1);
	}
}
void init()
{
	dfs(0,1,0,1);
	for(int k=1;k<=23;k++)
	for(int i=1;i<=n;i++)
	fa[i][k]=fa[fa[i][k-1]][k-1];
}
int lca(int u,int v)
{
	if(dep[u]>dep[v]) swap(u,v);
	for(int k=20;k>=0;k--)
	if(dep[v]-dep[u]>=(1<<k))
	v=fa[v][k];
	if(u==v) return u;
	for(int k=20;k>=0;k--)
	if(fa[u][k]!=fa[v][k])
	u=fa[u][k],v=fa[v][k];
	return fa[u][0];
}
int main()
{
	int u,v,k;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	sz=unique(b+1,b+1+n)-b-1;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	init();
	int ans=0;
	while(m--)
	{
		scanf("%d%d%d",&u,&v,&k);
		u=u^ans;
		int comlca=lca(u,v);
		ans=b[qu(rt[u],rt[v],rt[comlca],rt[fa[comlca][0]],1,sz,k)];
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/89485436