洛谷 P3834 【模板】可持久化线段树 1(主席树)

题目背景

这是个非常经典的主席树入门题——静态区间第K

数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

输入输出格式

输入格式:

第一行包含两个正整数NM,分别表示序列的长度和查询的个数。

第二行包含N个正整数,表示这个序列各项的数字。

接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l,r][l,r] 内的第k小值。

输出格式:

输出包含k行,每行1个正整数,依次表示每一次查询的结果

输入输出样例

输入样例#1 

5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1

输出样例#1

6405
15770
26287
25957
26287

说明

数据范围

对于20%的数据满足: 1N,M10

对于50%的数据满足: 1N,M103

对于80%的数据满足: 1N,M105

对于100%的数据满足: 1N,M2105

对于数列中的所有数 a_iai ,均满足 109ai109

样例数据说明

N=5,数列长度为5,数列从第一项开始依次为 [25957,6405, 15770, 26287, 26465 ][25957,6405,15770,26287,26465]

第一次查询为 [2,2][2,2] 区间内的第一小值,即为6405

第二次查询为 [3,4][3,4] 区间内的第一小值,即为15770

第三次查询为 [4,5][4,5] 区间内的第一小值,即为26287

第四次查询为 [1,2][1,2] 区间内的第二小值,即为25957

第五次查询为 [4,4][4,4] 区间内的第一小值,即为26287

题解:最经典的主席树模板题。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 200010
int n,m,a[N],b[N],L[N<<5],R[N<<5],T[N],sum[N<<5];
int cnt=0,t,x,y,z;
using namespace std;
inline int read()
{
	int f=1,x=0;
	char ch=getchar();
	if (ch=='-')
	{
		f=-1;
		ch=getchar();
	}
	while ((ch<'0')||(ch>'9')) ch=getchar();
	while ((ch>='0')&&(ch<='9'))
	{
		x=x*10+ch-48;
		ch=getchar();
	}
	return f*x;
}
inline int build(int l,int r)
{
	int root=++cnt;
	sum[root]=0;
	if (l<r)
	{
		L[root]=build(l,(l+r)/2);
		R[root]=build((l+r)/2+1,r);
	}
	return root;
}
inline int update(int pre,int l,int r,int p)
{
	int root=++cnt;
	L[root]=L[pre];
	R[root]=R[pre];
	sum[root]=sum[pre]+1;
	if (l<r)
	{
		if (p<=(l+r)/2) 
	      L[root]=update(L[pre],l,(l+r)/2,p);
	      else
	      R[root]=update(R[pre],(l+r)/2+1,r,p);
	}
	return root;
}
inline int query(int u,int v,int l,int r,int p)
{
	if (l>=r) return l;
	int xx=sum[L[v]]-sum[L[u]];
	if (xx>=p) 
	  return query(L[u],L[v],l,(l+r)/2,p);
	  else
	  return query(R[u],R[v],(l+r)/2+1,r,p-xx);
}
int main()
{
	freopen("1.in","r",stdin);
	n=read(),m=read();
	for (int i=1;i<=n;i++) 
	{
		a[i]=read();
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	t=unique(b+1,b+1+n)-b-1;
	T[0]=build(1,t);
	for (int i=1;i<=n;i++)
	{
		int p=lower_bound(b+1,b+t+1,a[i])-b;
		T[i]=update(T[i-1],1,t,p);
	}
	for (int i=1;i<=m;i++)
	{
		x=read(),y=read(),z=read();
		int tt=query(T[x-1],T[y],1,t,z);
		printf("%d\n",b[tt]);
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/zhouhongkai06/article/details/80645268