// 主席树 O(nlognlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 200005
#define lc(x) tr[x].l
#define rc(x) tr[x].r
struct node{
  int l,r,s; //s:节点值域中有多少个数
}tr[N*20];
int root[N],idx;
int n,m,a[N],b[N];

void insert(int x,int &y,int l,int r,int pos){
  y=++idx; //开点
  tr[y]=tr[x]; tr[y].s++;
  if(l==r) return;
  int m=l+r>>1;
  if(pos<=m) insert(lc(x),lc(y),l,m,pos);
  else insert(rc(x),rc(y),m+1,r,pos);
}
int query(int x,int y,int l,int r,int k){
  if(l==r) return l;
  int m=l+r>>1;
  int s=tr[lc(y)].s-tr[lc(x)].s;
  if(k<=s) return query(lc(x),lc(y),l,m,k);
  else return query(rc(x),rc(y),m+1,r,k-s);
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1; i<=n; i++){
    scanf("%d",&a[i]); b[i]=a[i];
  }
  sort(b+1,b+n+1);
  int bn=unique(b+1,b+n+1)-b-1; //去重后的个数

  for(int i=1; i<=n; i++){
    int id=lower_bound(b+1,b+bn+1,a[i])-b;//下标
    insert(root[i-1],root[i],1,bn,id);
  }
  while(m--){
    int l,r,k; scanf("%d%d%d",&l,&r,&k);
    int id=query(root[l-1],root[r],1,bn,k);
    printf("%d\n",b[id]);
  }
}
#include<bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
const int maxn=2e5+5;
struct Node{
	int l,r;
	int cnt;
};
Node tree[maxn*40];
int root[maxn];
int idx=0;
vector<ll>nums,sorted;
int get_id(int x){
	return lower_bound(sorted.begin(),sorted.end(),x)-sorted.begin()+1;
}
void init_dis(const vector<ll>&data){
	nums=data;
	sorted=nums;
	sort(sorted.begin(),sorted.end());
	sorted.erase(unique(sorted.begin(),sorted.end()),sorted.end());	
}
int build (int l,int r){
	int node=++idx;
	tree[node].cnt=0;
	if(l==r)return node;
	int mid=(l+r)/2;
	tree[node].l=build(l,mid);
	tree[node].r=build(mid+1,r);
	return node;
}
void insert(int x,int &y,int l,int r,int v){
	y=++idx;
	tree[y]=tree[x];
	tree[y].cnt++;
	if(l==r)return ;
	int m=(l+r)/2;
	if(v<=m){
		insert(tree[x].l,tree[y].l,l,m,v);
	}
	else{
		insert(tree[x].r,tree[y].r,m+1,r,v);
	}
}
int query(int u,int v,int l,int r,int k){
	if(l==r)return l;
	int mid=(l+r)/2;
	int cnt=tree[tree[v].l].cnt-tree[tree[u].l].cnt;
	if(k<=cnt){
		return query(tree[u].l,tree[v].l,l,mid,k);
	}
	else{
		return query(tree[u].r,tree[v].r,mid+1,r,k-cnt);
	}
}
void init(const vector<ll>& data){
	init_dis(data);
	root[0]=build(1,sorted.size());
	for(int i=1;i<=data.size();i++){
		int x=get_id(data[i-1]);
		insert(root[i-1],root[i],1,sorted.size(),x);
	}
}
ll solve(int l,int r,int k){
	int order=query(root[l-1],root[r],1,sorted.size(),k);
	return sorted[order-1];
}
signed main(){
	int n,m;
	cin>>n>>m;
	vector<ll>data;
	for(int i=1;i<=n;i++){
		ll da;
		cin>>da;
		data.push_back(da);
	}
	init(data);
	for(int i=1;i<=m;i++){
		int l,r,k;
		cin>>l>>r>>k;
		ll ans=solve(l,r,k);
		cout<<ans<<endl;
	}
	
}

下面是维护数组修改元素的:

#include<bits/stdc++.h>
using namespace std;
struct Node{
	int l,r;
	int val;
};
const int maxn=1e6+5;
Node tree[40*maxn];
int root[maxn];
int idx=0;
int build(int l,int r,const vector<int>&arr){
	int node=++idx;
	if(l==r){
		tree[node].val=arr[l-1];
		return node;
	}
	int mid=(l+r)/2;
	tree[node].l=build(l,mid,arr);
	tree[node].r=build(mid+1,r,arr);
	return node;
}
void update(int x,int &y,int l,int r,int pos,int v){
	y=++idx;
	tree[y]=tree[x];
	if(l==r){
		tree[y].val=v;
		return ;
	}
	int m=(l+r)/2;
	if(pos<=m){
		update(tree[x].l,tree[y].l,l,m,pos,v);
	}
	else{
		update(tree[x].r,tree[y].r,m+1,r,pos,v);
	}
}
int query(int node,int l,int r,int pos){
	if(l==r){
		return tree[node].val;
	}
	int mid=(l+r)/2;
	if(pos<=mid){
		return query(tree[node].l,l,mid,pos);
	}
	else return query(tree[node].r,mid+1,r,pos);
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin>>n>>m;
	vector<int>arr(n);
	for(int i=0;i<n;i++){
		cin>>arr[i];
	}
	root[0]=build(1,n,arr);
	int cv=0;
	while(m--){
		int v,op;
		cin>>v>>op;
		if(op==1){
			int p,c;
			cin>>p>>c;
			cv++;
			update(root[v],root[cv],1,n,p,c);
		}
		else{
			int p;
			cin>>p;
			cv++;
			int val=query(root[v],1,n,p);
			cout<<val<<"\n";
			root[cv]=root[v];
		}
		
	}
}