离散化 主席树(可持久线段树)P3834

 unique 返回的是去重后的尾地址,所以减去初始地址。从第一位开始,就还要-1(与lower_bound不同)

切记,没有排序前只是去掉相邻的重复元素,如果要真正去重就要排序。所以先sort再unique

去重是因为:线段树的各叶节点不能重复。而出现的次数不要紧,因为每加入一个数,会更新一个版本的树

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int tot,n,m,ver[maxn],a[maxn],b[maxn];
struct tt{
	int l,r,val;
}tree[maxn<<5];//n是maxn    <<5是logn,可开大一点
int build(int l,int r){
	int rt=++tot;
	tree[rt].val=0;
	tree[rt].l=rt;
	tree[rt].r=rt;
	return rt;
}
void pushup(int root){
	tree[root].val=tree[tree[root].l].val+tree[tree[root].r].val;
}
int change(int node,int l,int r,int pos){
	int root=++tot;
	tt &rt=tree[root];
	rt=tree[node];
	if(l==r){
		rt.val++;
		return root;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) rt.l=change(rt.l,l,mid,pos);
	else rt.r=change(rt.r,mid+1,r,pos);
	pushup(root);
	return root;
}
int query(int per,int lst,int l,int r,int k){
	if(l==r) return l;
	tt &pp=tree[per],&ll=tree[lst];	
	int tx=tree[ll.l].val-tree[pp.l].val;
	int mid=(l+r)>>1;
	if(tx>=k) return query(pp.l,ll.l,l,mid,k);
	else  return query(pp.r,ll.r,mid+1,r,k-tx);
}
int main(){
	int x,l,r,k,len;
		tot=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			b[i]=a[i];			
		}

		sort(b+1,b+1+n);
		len=unique(b+1,b+1+n)-(b+1);
		ver[0]=build(1,len);
        //去重,并求有几个不重复的数
		for(int i=1;i<=n;i++){
			int tem=lower_bound(b+1,b+1+len,a[i])-b;//离散化
			ver[i]=change(ver[i-1],1,len,tem);
		}
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&l,&r,&k);
			printf("%d\n",b[query(ver[l-1],ver[r],1,len,k)]);
		}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_50904510/article/details/119984902
今日推荐