静态区间第K小 (主席树模板 洛谷3834 )
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; struct Tree{ int l,r,s; }tree[maxn*32];//开32倍 struct node{ int w,pos; }a[maxn]; int b[maxn],c[maxn],root[maxn]; //b 离散后的位置 c原值 root个树的根 int k=0,tot=0; void dc(int n)//离散化 { b[a[1].pos]=++tot; c[tot]=a[1].w; for(int i=2;i<=n;i++) { if(a[i].w!=a[i-1].w) tot++; b[a[i].pos]=tot; c[tot]=a[i].w; } } int cmp(node a,node b) { return a.w<b.w; } int built(int l,int r)//建树 防止爆内存 静态分配空间 { int now=++k; int mid=(l+r)>>1; if(l<r) { tree[now].l=built(l,mid); tree[now].r=built(mid+1,r); } return now; } int updata(int pre,int x,int l,int r)//更新 { int mid=(l+r)>>1; int now=++k; tree[now].s=tree[pre].s+1;//区间内的数的出现次数++ tree[now].l=tree[pre].l;//将左右节点先指向原树 tree[now].r=tree[pre].r; if(l<r)//新建树链 { if(x<=mid) tree[now].l=updata(tree[pre].l,x,l,mid); else tree[now].r=updata(tree[pre].r,x,mid+1,r); } return now; } int query(int u,int v,int x,int l,int r)//查询 { int mid=(l+r)>>1;//找到第k小值 if(l==r) return l; //第r棵线段树左儿子-第(l-1)棵线段树左儿子的值 int t=tree[tree[v].l].s-tree[tree[u].l].s; //cout<<t<<endl; return x<=t?query(tree[u].l,tree[v].l,x,l,mid):query(tree[u].r,tree[v].r,x-t,mid+1,r); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i].w); a[i].pos=i; } sort(a+1,a+1+n,cmp); dc(n); // for(int i=1;i<=n;i++) // cout<<a[i].w<<" ";cout<<endl; // for(int i=1;i<=n;i++) // cout<<b[i]<<" ";cout<<endl; // for(int i=1;i<=n;i++) // cout<<c[i]<<" ";cout<<endl; root[0]=built(1,tot); for(int i=1;i<=n;i++)//建n棵线段树,边加点边建树 root[i]=updata(root[i-1],b[i],1,tot); for(int i=1;i<=m;i++) { int l,r,x; scanf("%d%d%d",&l,&r,&x); // cout<<query(l-1,r,x,1,tot)<<endl; //[l,r]就等价于 第r棵线段树-第(l-1)棵线段树 的k小值,返回该节点映射的值 printf("%d\n",c[query(root[l-1],root[r],x,1,tot)]); } return 0; }