可持久化线段树
可持久化权值线段树(主席树)
一个常见模板题静态区间第k大
一个容易出现的思路:先对数组在值域上进行离散化,那么建树过程可以变成每次在离散的值域区间上单点权值+1。“可持久化”用logn的时间和空间来维护不同版本。
每次找区间第k大=>两个不同的历史版本找最小的r,使得两版本在[1,r]的前缀和之差恰好为k。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T &x){
x=0;T fl=1;char tmp=getchar();
while(tmp<'0'||tmp>'9')fl=tmp=='-'?-fl:fl,tmp=getchar();
while(tmp>='0'&&tmp<='9')x=(x<<3)+(x<<1)+tmp-'0',tmp=getchar();
x=x*fl;
}
const ll mod=1e9+7;
const int maxn=2e5+100;
int a[maxn],b[maxn];
int n,m,q;
struct node{
int l,r,val;
}t[maxn<<5];
int root[maxn];int clk;
int build(int l,int r){
int rt=++clk;
t[clk].val=0;
if(r>l){
int mid=l+r>>1;
t[rt].l=build(l,mid);
t[rt].r=build(mid+1,r);
}
return rt;
}
int insert(int u,int l,int r,int pos){
int rt=++clk;
t[rt].val=t[u].val+1;
if(r>l){
int mid=l+r>>1;
if(pos<=mid){
t[rt].r=t[u].r;
t[rt].l=insert(t[u].l,l,mid,pos);
}
else{
t[rt].l=t[u].l;
t[rt].r=insert(t[u].r,mid+1,r,pos);
}
}
return rt;
}
int query(int u,int v,int l,int r,int cnt){
if(l>=r) return l;
int mid=l+r>>1;
if(t[t[v].l].val-t[t[u].l].val>=cnt){
return query(t[u].l,t[v].l,l,mid,cnt);
}
else
return query(t[u].r,t[v].r,mid+1,r,cnt-(t[t[v].l].val-t[t[u].l].val));
}
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++)
read(a[i]),b[i]=a[i];
sort(b+1,b+n+1);
m=unique(b+1,b+n+1)-b-1;
root[0]=build(1,m);
for(int i=1;i<=n;i++){
int key=lower_bound(b+1,b+m+1,a[i])-b;
root[i]=insert(root[i-1],1,m,key);
}
while(q--){
int l,r,k;
read(l),read(r),read(k);
printf("%d\n",b[query(root[l-1],root[r],1,m,k)]);
}
return 0;
}