【BZOJ 2588】 Spoj 10628. Count on a tree|树上K大|树链剖分|主席树

我沙茶

我沙茶

我沙茶

傻到去写链剖! 本来求个LCA又好写又快.....

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 100010

int team[MAXN],head,tail;
int fa[MAXN],son[MAXN],size[MAXN],loc[MAXN],top[MAXN],depth[MAXN];

int tot,g[MAXN*2],nnext[MAXN*2],num[MAXN*2];
void Add(int x,int y)
{
	tot++;
	nnext[tot]=g[x];
	g[x]=tot;
	num[tot]=y;
}

void Lian_Pou()
{
	team[++tail]=1;
	depth[1]=1;
	while(head<tail)
	{
		int x=team[++head];
		for(int i=g[x];i;i=nnext[i])
		{
			int tmp=num[i];
			if(depth[tmp]!=0) continue ;
			fa[tmp]=x;
			depth[tmp]=depth[x]+1;
			team[++tail]=tmp;
		}
	}
	for(int i=tail;i>=1;i--)
	{
		int x=team[i];
		size[x]=1;
		for(int j=g[x];j;j=nnext[j])
		{
			int tmp=num[j];
			if(tmp==fa[x]) continue ;
			size[x] += size[tmp];
			if(size[tmp]>size[son[x]]) son[x]=tmp;
		}
	}
	loc[1]=1;
	top[1]=1;
	for(int i=1;i<=tail;i++)
	{
		int x=team[i];
		int cnt=loc[x];
		if(son[x]!=0)
		{
			loc[son[x]]=cnt+1;
			top[son[x]]=top[x];
			cnt+=size[son[x]];
		}
		for(int j=g[x];j;j=nnext[j])
		{
			int tmp=num[j];
			if(tmp==fa[x]||tmp==son[x]) continue ;
			loc[tmp]=cnt+1;
			top[tmp]=tmp;
			cnt+=size[tmp];
		}
	}
}
struct INIT
{
	int num;
	int loc;
	int no;
} init[MAXN];
bool cmp(INIT a,INIT b) 
{
	return a.loc<b.loc;
}
bool cmp1(INIT a,INIT b)
{
	return a.num<b.num;
}

int cnt;
int seg_tot;
struct H
{
	int L,R;
	int sum;
}seg[MAXN*20];

void Seg_Add(int now,int l,int r,int x,int last)
{
	if(l==r) 
	{
		seg[now].sum=seg[last].sum+1;;
		return ;
	}
	int mid=(l+r)/2;
	if(x<=mid) 
	{
		seg[now].L=++seg_tot;
		seg[now].R=seg[last].R;
		last=seg[last].L;
		Seg_Add(seg[now].L,l,mid,x,last);
	}
	else
	{
		seg[now].R=++seg_tot;
		seg[now].L=seg[last].L;
		last=seg[last].R;
		Seg_Add(seg[now].R,mid+1,r,x,last);
	}
	seg[now].sum=seg[seg[now].L].sum+seg[seg[now].R].sum;
}
int hash[MAXN];
int root[MAXN];
int LL[MAXN],RR[MAXN],LN,RN;
void Solve(int x,int y)
{
	LN=0;
	RN=0;
	while(top[x]!=top[y])
	{
		if(depth[top[x]]<depth[top[y]]) swap(x,y);
		LL[++LN]=root[loc[top[x]]-1];
		RR[++RN]=root[loc[x]];
		x=fa[top[x]];
	}
	if(depth[x]<depth[y]) swap(x,y);
	LL[++LN]=root[loc[y]-1];
	RR[++RN]=root[loc[x]];
}

int Q(int l,int r,int k)
{	

	if(l==r) return l;
	int S=0;
	for(int i=1;i<=LN;i++) 
	{
		S-=seg[seg[LL[i]].L].sum;
		S+=seg[seg[RR[i]].L].sum;
	}

	int mid=(l+r)/2;
	if(k<=S)
	{
		for(int i=1;i<=LN;i++) LL[i]=seg[LL[i]].L;
		for(int i=1;i<=RN;i++) RR[i]=seg[RR[i]].L;
		return Q(l,mid,k);
	}
	else
	{
		for(int i=1;i<=LN;i++) LL[i]=seg[LL[i]].R;
		for(int i=1;i<=RN;i++) RR[i]=seg[RR[i]].R;
		k-=S;
		return Q(mid+1,r,k);
	}
}

int main()
{
//	freopen("a.in","r",stdin);
//	freopen("wa.out","w",stdout);
	int n,m;
	cin >> n >> m;
	for(int i=1;i<=n;i++) scanf("%d",&init[i].num);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		Add(x,y);
		Add(y,x);
	}
	Lian_Pou();
	for(int i=1;i<=n;i++) init[i].loc=loc[i];
	sort(init+1,init+1+n,cmp1);
	init[1].no=1;
	for(int i=2;i<=n;i++)
	 	if(init[i].num!=init[i-1].num)
	 		init[i].no=init[i-1].no+1;
	 	else init[i].no=init[i-1].no;
	cnt=init[n].no;
	for(int i=1;i<=n;i++) hash[init[i].no]=init[i].num;
	sort(init+1,init+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		root[i]=++seg_tot;
		Seg_Add(root[i],1,cnt,init[i].no,root[i-1]);
	}
	int last=0;
	for(int i=1;i<=m;i++)
	{
		int u,v,k;
		scanf("%d %d %d",&u,&v,&k);
		u^=last;
		Solve(u,v);
		last=hash[Q(1,cnt,k)];
		if(i!=m) printf("%d\n",last);
		else printf("%d",last);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值