[可持久化权值线段树] [模板] [数组版本]
[可持久化权值线段树] [模板] [数组版本]
\[1 \leq n \leq 2e5\\
|a_i| \leq 1e9
\]
感觉动态开点用指针好理解一点
但是太难调试了,还是数组版本吧
代码
int a[maxn],b[maxn],len;
inline int getid(int val){
return lower_bound(b + 1,b + len + 1,val) - b;
}
struct ZXS{
int cnt;
vector<int> sum,L,R,T;
ZXS(int n):cnt(0),sum(n * 40),L(n * 40),R(n * 40),T(n + 5) {}
int build(int l,int r){
int rt = ++cnt;
sum[rt] = 0;
int mid = l + r >> 1;
if(l < r) {
L[rt] = build(l,mid);
R[rt] = build(mid + 1,r);
}
return rt;
}
int update(int pre,int l,int r,int x){
int rt = ++cnt;
L[rt] = L[pre],R[rt] = R[pre];
sum[rt] = sum[pre] + 1;
int mid = l + r >> 1;
if(l < r) {
if(x <= mid) L[rt] = update(L[pre],l,mid,x);
else R[rt] = update(R[pre],mid + 1,r,x);
}
return rt;
}
int query(int lt,int rt,int l,int r,int k) {
if(l >= r) return l;
int x = sum[L[rt]] - sum[L[lt]];
int mid = l + r >> 1;
if(x >= k) return query(L[lt],L[rt],l,mid,k);
else return query(R[lt],R[rt],mid + 1,r,k - x);
}
};
int main(){
int n = rd();
int q = rd();
for(int i = 1;i <= n;i++) {
a[i] = rd();
b[i] = a[i];
}
sort(b + 1,b + n + 1);
len = unique(b + 1,b + n + 1) - (b + 1);
ZXS seg(n);
seg.T[0] = seg.build(1,len);
for(int i = 1;i <= n;i++){
seg.T[i] = seg.update(seg.T[i - 1],1,len,getid(a[i]));
}
while(q--){
int l = rd();
int r = rd();
int k = rd();
printf("%d\n",b[seg.query(seg.T[l - 1],seg.T[r],1,len,k)]);
}
}