POJ2104 POJ2761 区间第K大 主席树
来源:互联网 发布:电脑有趣的软件 编辑:程序博客网 时间:2024/05/17 23:21
题意
查询一个区间第k大的数
解法
之前只是套版,没仔细看模板里的代码很吃亏,重新仔细看了一遍,理解更深了一点。
这道题里面建了N个线段树,第i个线段树维护后缀[i…n]中数字在大小为[L,R]的区间里面的个数,但是数字很大,离散化一下就好(用unique)
精髓在查询里面,查询区间[L,R]里面第K大的数字,其实就是找到一个mid,使sum[1,mid] = k(在T[L]上查询的结果 - T[R+1]上查询的结果就是在[L,R]上查询的结果) 使用二分即可,在线段树上二分其实就是相当于在树上进行二分查找。
代码
/* ***********************************************Author :czw注:使用了kuangbin大神的主席树模板************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;/* * 给出一个序列,查询区间内有多少个不相同的数 */namespace PST { const int MAXN = 100005; const int M = MAXN * 50; int tot; int T[M],lson[M],rson[M],c[M]; int n; void init(int _n) { tot = 0; n = _n; } int build(int l = 1,int r = n) { int root = tot++; c[root] = 0; if(l != r) { int mid = (l+r)>>1; lson[root] = build(l,mid); rson[root] = build(mid+1,r); } return root; } int update(int root,int pos,int val) { int newroot = tot++, tmp = newroot; c[newroot] = c[root] + val; int l = 1, r = n; while(l < r) { int mid = (l+r)>>1; if(pos <= mid) { lson[newroot] = tot++; rson[newroot] = rson[root]; newroot = lson[newroot]; root = lson[root]; r = mid; } else { rson[newroot] = tot++; lson[newroot] = lson[root]; newroot = rson[newroot]; root = rson[root]; l = mid+1; } c[newroot] = c[root] + val; } return tmp; } int queryK(int lroot, int rroot, int k) { //后缀[l...n],后缀[r+1...n],第k大 //注意二分的形式要与上面build相同,才能保证区间的对应关系 int l = 1, r = n, mid; while(l < r) { mid = (l + r) >> 1; if(c[lson[lroot]] - c[lson[rroot]] >= k) { r = mid; lroot = lson[lroot]; rroot = lson[rroot]; } else { k -= c[lson[lroot]] - c[lson[rroot]]; l = mid + 1; lroot = rson[lroot]; rroot = rson[rroot]; } } return l; }}const int SIZE = PST::MAXN;int A[SIZE];int B[SIZE];int bc;int init(int &n) { for(int i = 1; i <= n; i++) { B[i] = A[i]; } sort(B+1, B+1+n); bc = unique(B+1, B+1+n) - B - 1;}int Rank(int a) { return lower_bound(B+1, B+bc+1, a) - B;}int main() { int n, q; while(~scanf("%d%d",&n,&q)) { for(int i = 1; i <= n; i++) { scanf("%d",&A[i]); } init(n); PST::init(bc); PST::T[n+1] = PST::build(); for(int i = n; i >= 1; i--) { PST::T[i] = PST::update(PST::T[i+1], Rank(A[i]), 1); } while(q--) { int l, r, k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",B[PST::queryK(PST::T[l],PST::T[r+1],k)]); } }}
0 0
- poj2761&&poj2104 主席树(静态区间第K大)
- POJ2104 POJ2761 区间第K大 主席树
- poj2104 主席树区间第k大
- poj2104区间K大 主席树
- 主席树(静态区间第k大)+poj2014+poj2761+hdu2665
- POJ2104-K-th Number-区间第k大-可持久化线段树/主席树
- poj2104 K-th Number(静态区间k大,主席树)
- 【主席树】poj2104 K-th Number && poj2761 Feed the dogs
- 可持久化线段树(主席树)(图文并茂详解)【poj2104】【区间第k大】
- 【poj2104】不带修改的区间第k大 主席树
- 主席树 HDOJ2665 && POJ2104 && POJ2761
- 主席树经典题目 区间k大值 poj2104
- poj2104 区间第K大
- hdu2665/poj2104;poj2761 区间第k小 函数式线段树
- poj2761(静态区间第k大,treap)
- 主席树---求第k大的数 poj2104
- 主席树解决区间第k大
- 区间第k大(主席树)
- 深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)
- Java.Web学习笔记 Servlet
- 计算社会初探
- Android Studio 插件 CodeGlance 快速定位代码
- 谷歌插件Postman下载安装
- POJ2104 POJ2761 区间第K大 主席树
- ArrayList源码解析 给jdk写注释系列之jdk1.6容器(1)
- 领域特性模块集
- 数据结构实验之栈四:括号匹配
- 二叉树的非递归遍历
- 文件上传(利用oss 和plupload)
- 欢迎使用CSDN-markdown编辑器
- iOS 简易音乐播放界面
- Hive 合并小文件