可持久化线段树(主席树)

给定 n 个整数构成的序列 a,将对于指定的闭区间 [l,r] 查询其区间内的第 k 小值。

  • 题目一开始的离散化复杂度为O(nlogn),构建基础主席树复杂度为O(nlogn),统计并插入的复杂度是O(nlogn+nlogn)=O(nlogn),询问的复杂度是O(mlogn)。复杂度总和就是O((m+n)logn)
#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]; vector<int> b; void build(int &x,int l,int r){ x=++idx; if(l==r) return; int m=l+r>>1; build(lc(x),l,m); build(rc(x),m+1,r); } void insert(int x,int &y,int l,int r,int k){ y=++idx; tr[y]=tr[x]; tr[y].s++; if(l==r) return; int m=l+r>>1; if(k<=m) insert(lc(x),lc(y),l,m,k); else insert(rc(x),rc(y),m+1,r,k); } 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.push_back(a[i]); } sort(b.begin(),b.end()); b.erase(unique(b.begin(),b.end()),b.end()); int bn=b.size(); build(root[0],1,bn); for(int i=1; i<=n; i++){ int id=lower_bound(b.begin(),b.end(),a[i])-b.begin()+1; 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)-1; printf("%d\n",b[id]); } return 0; }

__EOF__

本文作者爱飞鱼
本文链接https://www.cnblogs.com/mathiter/p/17892110.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   potential-star  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示