主席树模板

const int MAX_N=101000;
int num=0;
struct skt{
    int l,r,sum;
}f[MAX_N*40];
int root[MAX_N],b[MAX_N];
void build(int k,int l,int r){
  if(l==r){
   f[k].sum=0;
   if(k>num)
   num=k;
   return;
}
  else{
   int mid=(l+r)>>1;
   f[k].l=k<<1,f[k].r=k<<1|1;
   build(k<<1,l,mid);
   build(k<<1|1,mid+1,r);
  }
}
void add(int k,int k1,int l,int r,int x){
  if(l==r){
  	f[k1].sum=f[k].sum;
    f[k1].sum++;
    return;
 }
  else{
    int mid=(l+r)>>1;
    if(x<=mid){
      f[k1].l=++num;
      f[k1].r=f[k].r;
      add(f[k].l,f[k1].l,l,mid,x);
    }
    else{
      f[k1].l=f[k].l;
      f[k1].r=++num;
      add(f[k].r,f[k1].r,mid+1,r,x);
    }
    f[k1].sum=f[f[k1].l].sum+f[f[k1].r].sum;
  }
}
int find(int k,int k1,int l,int r,int x){
  if(l==r)
  return l;
  else{
    int mid=(l+r)>>1;
    int sl=f[f[k1].l].sum-f[f[k].l].sum;
    if(sl>=x){
      return find(f[k].l,f[k1].l,l,mid,x);
    }
    else{
      return find(f[k].r,f[k1].r,mid+1,r,x-sl);
  }
  }
}

//主席树用法


 len=max_;
 build(1,1,len);
 for(i=1;i<=n;i++){
  root[i]=++num;
  add(root[i-1],root[i],1,len,b[i]);
 }
 for(i=0;i<m;i++){
  scanf("%d%d%d",&x,&y,&z);
  printf("%d\n",find(root[x-1],root[y],1,len,z));
 }

离散化主席树

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=201000;
int num=0;
struct skt{
    int l,r,sum;
}f[MAX_N*40];
int root[MAX_N],b[MAX_N];
void build(int k,int l,int r){
  if(l==r){
   f[k].sum=0;
   if(k>num)
   num=k;
   return;
}
  else{
   int mid=(l+r)>>1;
   f[k].l=k<<1,f[k].r=k<<1|1;
   build(k<<1,l,mid);
   build(k<<1|1,mid+1,r);
  }
}
void add(int k,int k1,int l,int r,int x){
  if(l==r){
   f[k1].sum=f[k].sum;
    f[k1].sum++;
    return;
 }
  else{
    int mid=(l+r)>>1;
    if(x<=mid){
      f[k1].l=++num;
      f[k1].r=f[k].r;
      add(f[k].l,f[k1].l,l,mid,x);
    }
    else{
      f[k1].l=f[k].l;
      f[k1].r=++num;
      add(f[k].r,f[k1].r,mid+1,r,x);
    }
    f[k1].sum=f[f[k1].l].sum+f[f[k1].r].sum;
  }
}
int find(int k,int k1,int l,int r,int x){
  if(l==r)
  return l;
  else{
    int mid=(l+r)>>1;
    int sl=f[f[k1].l].sum-f[f[k].l].sum;
    if(sl>=x){
      return find(f[k].l,f[k1].l,l,mid,x);
    }
    else{
      return find(f[k].r,f[k1].r,mid+1,r,x-sl);
  }
  }
}
int a[MAX_N],sub_a[MAX_N],ans[MAX_N];
int main(void){
    int n,m,i,x,y,z;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sub_a[i-1]=a[i];
    }
    sort(sub_a,sub_a+n);
    int nn=unique(sub_a,sub_a+n)-sub_a;
    for(i=1;i<=n;i++){
        b[i]=lower_bound(sub_a,sub_a+nn,a[i])-sub_a+1;
        ans[b[i]]=a[i];
    }
    int len=nn;
    build(1,1,len);
    for(i=1;i<=n;i++){
        root[i]=++num;
        add(root[i-1],root[i],1,len,b[i]);
    }
    for(i=0;i<m;i++){
        scanf("%d%d%d",&x,&y,&z);
        printf("%d\n",ans[find(root[x-1],root[y],1,len,z)]);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值