(本人的模板)
Description
题目背景
这是个非常经典的主席树入门题——静态区间第 kk 小数据已经过加强,请使用主席树。同时请注意常数优化
题目描述
如题,给定 nn 个整数构成的序列,将对于指定的闭区间查询其区间内的第 kk 小值。
输入格式
第一行包含两个正整数 n,mn,m,分别表示序列的长度和查询的个数。第二行包含 nn 个整数,表示这个序列各项的数字。接下来 mm 行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第 kk 小值。
输出格式
输出包含 kk 行,每行一个整数,依次表示每一次查询的结果
Code
#include <cstdio> #include <cstdlib> #include <algorithm> using namespace std; const int N=2e5+10; struct node { int lc,rc,sum; }f[N*40]; struct mode { int v,id; bool operator <(const mode &o)const { return v<o.v; } }a[N]; int n,m,rt[N],d[N],l,r,k,tot,cnt,re[N]; void build(int l,int r,int &x,int y,int pos) { x=++tot; f[x]=f[y],f[x].sum++; if(l==r) return ; int mid=(l+r)>>1; if(pos<=mid) build(l,mid,f[x].lc,f[y].lc,pos); else build(mid+1,r,f[x].rc,f[y].rc,pos); } int ans(int l,int r,int x,int y,int k) { if(l>=r) return l; int cnt=f[f[x].lc].sum-f[f[y].lc].sum; int mid=(l+r)>>1; if(cnt>=k) return ans(l,mid,f[x].lc,f[y].lc,k); else return ans(mid+1,r,f[x].rc,f[y].rc,k-cnt); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i].v),a[i].id=i; sort(a+1,a+n+1); for(int i=1;i<=n;i++) { if(i==1 || a[i].v!=a[i-1].v) re[++cnt]=a[i].v; d[a[i].id]=cnt; } for(int i=1;i<=n;i++) build(1,n,rt[i],rt[i-1],d[i]); while(m--) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",re[ans(1,n,rt[r],rt[l-1],k)]); } return 0; }
原文地址:https://www.cnblogs.com/hsez-cyx/p/12267989.html
时间: 2024-10-13 16:36:29