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

题目

luogu3834

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define N 500005
#define M 10000000
using namespace std; 

int n,m,rk[N];
int root[N];

struct data{int id,num;}a[N];
bool cmp(data x,data y){return x.num<y.num;}
struct node{int l,r,sz;}T[M];

int cnt;
void insert(int &rt,int x,int y,int p)
{
	T[++cnt]=T[rt];rt=cnt;
	T[rt].sz++;//sz记录子树中被标记的结点个数 
	if(x==y) return;
	int mid=(x+y)>>1;
	if(p<=mid) insert(T[rt].l,x,mid,p);
	else insert(T[rt].r,mid+1,y,p);
}

int query(int ql,int qr,int x,int y,int k)
{
	if(x==y) return x;
	int t=T[T[qr].l].sz-T[T[ql].l].sz;
	int mid=(x+y)>>1;
	if(k<=t) return query(T[ql].l,T[qr].l,x,mid,k);
	else return query(T[ql].r,T[qr].r,mid+1,y,k-t);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].num),a[i].id=i;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++) rk[a[i].id]=i;//rk[i]记录在原序列的位置为i的数是第几大 
	for(int i=1;i<=n;i++)
	{
		root[i]=root[i-1];//root[i]记录前i个数构成的线段树的根
		insert(root[i],1,n,rk[i]); 
	}
	for(int i=1;i<=m;i++)
	{
		int x,y,k;scanf("%d%d%d",&x,&y,&k);
		printf("%d\n",a[query(root[x-1],root[y],1,n,k)].num);//类比sum[r]-sum[i-1] 
	}
	return 0;
}
posted @ 2017-09-26 19:18  XYZinc  阅读(141)  评论(0编辑  收藏  举报