看了很久的主席树,最后看https://blog.csdn.net/williamsun0122/article/details/77871278这篇终于看懂了
#include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]为原序列,h[]为去重化后序列 int sz[maxn],h[maxn]; int n,q,ql,qr,k,tot; void build(int& rt,int l,int r) //建空树 { rt = ++tot; sum[rt] = 0;//在该区间的元素个数 if(l==r) return; int mid = (l+r)>>1; build(L[rt],l,mid); build(R[rt],mid+1,r); } //对所有前缀更新树 void update(int& rt,int l,int r,int pre,int x) { rt = ++tot; L[rt]=L[pre]; R[rt]=R[pre];//新树继承上一个树,并在其中加入一个新元素 sum[rt] = sum[pre]+1;//元素个数加一 if(l==r) return; int mid = (l+r)>>1; if(x<=mid) update(L[rt],l,mid,L[pre],x); else update(R[rt],mid+1,r,R[pre],x); } int query(int s,int e,int l,int r,int k) { if(l==r) return l; int mid = (l+r)>>1; int res = sum[L[e]]-sum[L[s]]; //同时求左子树的个数相减,可以看做是一颗以[l.r]建立的线段树的左子树的元素的个数 if(k<=res) return query(L[s],L[e],l,mid,k); else return query(R[s],R[e],mid+1,r,k-res); } int main() { // int t; // scanf("%d",&t); // while(t--) // { scanf("%d%d",&n,&q); for(int i=1; i<=n; i++) scanf("%d",sz+i),h[i]=sz[i]; sort(h+1,h+1+n); int num = unique(h+1,h+1+n)-h-1;//去重后求剩余元素个数 tot=0; build(T[0],1,num);//初始化 for(int i=1; i<=n; i++) { //离散化后更新 int x=lower_bound(h+1,h+1+num,sz[i])-h;//求出当前元素的离散后值,从1开始所以是减h update(T[i],1,num,T[i-1],x); } while(q--) { scanf("%d%d%d",&ql,&qr,&k); int ans = query(T[ql-1],T[qr],1,num,k); printf("%d\n",h[ans]);//离散后的答案对应原去重后的下标 } // } return 0; }
原文地址:https://www.cnblogs.com/Json-Five/p/10018108.html
时间: 2024-10-12 12:33:46