11
29
2015
0

【bzoj2588】【SPOJ10628】Count on a tree

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 2926  Solved: 667
[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

HINT:
N,M<=100000
暴力自重。。。

Source

又一道主席树。

我们把Ti这棵线段树表示i到根节点的线段树,那么Ti可以由Tfa[i]得到,处理好线段树后,就可以解决询问了,对于每个询问u,v,k,只要根据tr[p1].sum+tr[p2].sum-tr[lca].sum-tr[fa[lca]].sum二分答案就可以了。

完美解决。

代码:

 

#include<cstdio>
#include<algorithm>
#define N 100010
using namespace std;
int n,n1,m,u,v,x,y,k,cnt,edgenum,ans;
int a[N],b[N],vet[2*N],next[2*N],head[N],f[N],d[N],son[N],num[N],top[N],root[N];
struct node{int l,r,sum;}tr[20*N];
void add(int u,int v)
{
	edgenum++;
	vet[edgenum]=v;
	next[edgenum]=head[u];
	head[u]=edgenum;
}
void dfs(int u,int fa,int dep)
{
	f[u]=fa;
	d[u]=dep;
	num[u]=1;
	int maxnum=0;
	for (int e=head[u];e;e=next[e])
	{
		int v=vet[e];
		if (v!=fa)
		{
			dfs(v,u,dep+1);
			num[u]+=num[v];
			if (num[v]>maxnum){maxnum=num[v];son[u]=v;}
		}
	}
}
void dfs(int u,int number)
{
	top[u]=number;
	if (!son[u]) return;
	dfs(son[u],number);
	for (int e=head[u];e;e=next[e])
	{
		int v=vet[e];
		if (v!=f[u]&&v!=son[u]) dfs(v,v);
	}
}
int lca(int u,int v)
{
	while (top[u]!=top[v])
	{
		if (d[top[u]]<d[top[v]]) swap(u,v);
		u=f[top[u]];
	}
	if (d[u]<d[v]) return u;else return v;
}
void change(int l,int r,int &p,int x)
{
	tr[++cnt]=tr[p];p=cnt;tr[p].sum++;
	if (l==r) return;
	int mid=(l+r)>>1;
	if (x<=mid) change(l,mid,tr[p].l,x);else change(mid+1,r,tr[p].r,x);
}
int ask(int x,int y,int k)
{
	int p1=root[x],p2=root[y],p3=root[lca(x,y)],p4=root[f[lca(x,y)]];
	int l=1,r=n;
	while (l<r)
	{
		int mid=(l+r)>>1;
		int t=tr[tr[p1].l].sum+tr[tr[p2].l].sum-tr[tr[p3].l].sum-tr[tr[p4].l].sum;
		if (t>=k) {p1=tr[p1].l;p2=tr[p2].l;p3=tr[p3].l;p4=tr[p4].l;r=mid;}else
		{p1=tr[p1].r;p2=tr[p2].r;p3=tr[p3].r;p4=tr[p4].r;k-=t;l=mid+1;}
	}
	return l;
}
void dfs(int u)
{
	root[u]=root[f[u]];
	change(1,n,root[u],a[u]);
	for (int e=head[u];e;e=next[e])
	{
		int v=vet[e];
		if (v!=f[u]) dfs(v);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	n1=unique(b+1,b+n+1)-b-1;
	for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n1+1,a[i])-b;
	for (int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	dfs(1,0,1);
	dfs(1,1);
	dfs(1);
	while (m--)
	{
		scanf("%d%d%d",&x,&y,&k);
		ans=b[ask(x^ans,y,k)];
		printf("%d",ans);
		if (m) printf("\n");
	}
}
Category: 主席树 | Tags: | Read Count: 318

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com