Count on a tree

树上主席树练习

luogu P2633

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100000
#define NlogN 2500000 
using namespace std;
int n,m,a[N+1],b[N+1],tree[N+1],l[NlogN],r[NlogN],sum[NlogN],deep[N+1],f[N+1][31],tot,len,mid,u,v,k,last;
int cnt,he[N<<2],nxt[N<<2],to[N<<2];
void add(int u,int v)
{
	cnt++;
	nxt[cnt]=he[u];
	he[u]=cnt;
	to[cnt]=v;
}
int build(int ll,int rr)
{
	int rt=++tot;
	if(ll<rr)
	{
		mid=(ll+rr)>>1;
		l[rt]=build(ll,mid);
		r[rt]=build(mid+1,rr);
	}
	return rt;
}
int update(int pre,int ll,int rr,int x)
{
	int rt=++tot;
	l[rt]=l[pre],r[rt]=r[pre],sum[rt]=sum[pre]+1;
	if(ll<rr)
	{
	  mid=(ll+rr)>>1;
	  if(x<=mid) l[rt]=update(l[pre],ll,mid,x);
	  else r[rt]=update(r[pre],mid+1,rr,x);	
	}
	return rt;
}
void build_tree(int pre,int now)
{
	deep[now]=deep[pre]+1,f[now][0]=pre;
	int rank=lower_bound(b+1,b+len+1,a[now])-b;
	tree[now]=update(tree[pre],1,len,rank);
	for(int i=he[now];i;i=nxt[i])
	{
		int g=to[i];
		if(g==pre) continue;
		build_tree(now,g);
	}
}
int lca(int q,int p)
{
	if(deep[q]>deep[p]) swap(q,p);
	int cz=deep[p]-deep[q],js=0;
	while(cz)
	{
		if(cz&1) p=f[p][js];
		js++,cz>>=1;
	}
	if(q==p) return q;
	for(int i=20;i>=0;i--) if(f[q][i]!=f[p][i]) q=f[q][i],p=f[p][i];
	return f[q][0];
}
int query(int t1,int t2,int t3,int t4,int ll,int rr,int id)
{
	if(ll==rr) return ll;
	int cz=sum[l[t1]]+sum[l[t2]]-sum[l[t3]]-sum[l[t4]];
	mid=(ll+rr)>>1;
	if(cz>=id) return query(l[t1],l[t2],l[t3],l[t4],ll,mid,id);
	else return query(r[t1],r[t2],r[t3],r[t4],mid+1,rr,id-cz);
}
int qread()
{
	char c=getchar();
	int x=0;
	while(c>'9'||c<'0') c=getchar();
	while(c<='9'&&c>='0') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x;
}
void ks(int xx)
{
	if(xx>=10) ks(xx/10);
	putchar(xx%10+'0');
}
int main()
{
	n=qread(),m=qread();
	for(int i=1;i<=n;i++) a[i]=qread(),b[i]=a[i];
	sort(b+1,b+n+1);
	len=unique(b+1,b+n+1)-b-1;
	tree[0]=build(1,len);//建零号主席树 
	for(int i=1,x,y;i<=n-1;i++) x=qread(),y=qread(),add(x,y),add(y,x);
	build_tree(0,1); 
	for(int i=1;i<=20;i++) //ST表 
	for(int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&k);
		last=u^last;
		int LCA=lca(last,v);
		last=b[query(tree[last],tree[v],tree[LCA],tree[f[LCA][0]],1,len,k)];
		ks(last),putchar('\n');
	}
	return 0;
} 
# COT - Count on a tree ## 题面翻译 # 本题必须使用 C++98 提交 给你一棵有n个结点的树,节点编号为1~n。 每个节点都有一个权值。 要求执行以下操作: U V K:求从节点u到节点v的第k小权值。 # 输入输出格式 ## 输入格式 第一行有两个整数n和m(n,m≤100000) 第二行有n个整数。 第i个整数表示第i个节点的权值。 接下来的n-1行中,每行包含两个整数u v,表示u和v之间有一条边。 接下来的m行,每行包含三个整数U V K,进行一次操作。 ## 输出格式 对于每个操作,输出结果。 ## 题目描述 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** ## 输入格式 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**. ## 输出格式 For each operation, print its result. ## 样例 #1 ### 样例输入 #1 ``` 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 ``` ### 样例输出 #1 ``` 2 8 9 105 7 ```
07-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值