题意:给定一个序列A,接下来又m个询问,每个询问输出A[L,R]中的第K大。(保证第k大存在)

思路:

  我想拿来练习“可持久化线段树”的,搜到这个比较巧的算法也可以解决这个问题,叫“归并树?。大概的思想就是和线段树一样,只是线段树上的每个非叶子节点是一个区间,等于该节点的两个孩子节点的区间的拼接起来,而每个区间内保持有序的。那么在查找时就找到这两个区间,二分枚举答案然后在询问区间[L,R]判断否排第k。这里二分答案只需要在线段树的根进行就行了,因为根这个区间是有序的。查找时[L,R]可能会是两个区间的拼接的[L,mid]+[mid+1,R],所以要在两个区间中分别判断val排行老几,然后加起来就是其在[L,R]的真实排行了,这可以用low_bound函数实现。

 //#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
int seq[N], tree[][N]; void build_tree(int L,int R,int depth)
{
if(L==R)
{
tree[depth][L]=seq[L];
return;
}
int mid=(L+R)>>;
build_tree(L,mid,depth+);
build_tree(mid+,R,depth+); //归并
int first=L, second=mid+, cnt=L;
while( first<=mid && second<=R )
{
if(tree[depth+][first]<tree[depth+][second])
tree[depth][cnt++]=tree[depth+][first++];
else
tree[depth][cnt++]=tree[depth+][second++];
}
if(first<=mid) //左边未完
{
for(int i=first; i<=mid; i++)
tree[depth][cnt++]=tree[depth+][i];
}
else //右边未完
{
for(int i=second; i<=R; i++)
tree[depth][cnt++]=tree[depth+][i];
}
} int query(int ll,int rr,int L,int R,int val,int depth) //返回val在[L,R]内的排名-1
{
if(L==ll && rr==R)
return lower_bound( &tree[depth][L], &tree[depth][R+], val)
-&tree[depth][L];
int mid=(ll+rr)>>, cnt=;
if( R<=mid ) cnt+=query(ll,mid, L,R, val,depth+);
else if( L>mid ) cnt+=query(mid+,rr, L,R, val,depth+);
else
{
cnt+=query(ll,mid, L,mid, val,depth+);
cnt+=query(mid+,rr, mid+,R, val,depth+);
}
return cnt;
} int main()
{
freopen("input.txt", "r", stdin);
int n, m, L, R, k;
while(~scanf("%d%d",&n,&m))
{
for(int i=; i<=n; i++) scanf("%d",&seq[i]);
build_tree(, n, ); while(m--)
{
scanf("%d%d%d",&L,&R,&k);
k--;
int ll=, rr=n;
while( ll<rr ) //在tree[0]中二分这个数
{
int mid=ll+(rr-ll+)/;
int pos=query(,n, L,R, tree[][mid],);
if( pos<=k ) ll=mid; //所查找的数太小了
else rr=mid-;
}
printf("%d\n", tree[][ll]);
}
}
return ;
}

AC代码

  主席树解法:按照序列的顺序seq[i],每插入1个点就建1棵树,而每棵树中有且只有seq[1,i]这个序列,而且不是按照seq[1,i]的顺序,而是变成在该树中是有序的。

  举例:假设有序列seq[4]={1,3,2,4}。

  插入第seq[1]后的结果:

  

  插入第seq[2]后的结果:

  

  插入第seq[3]后的结果:

  

  插入第seq[4]后的结果:

  

  观察上面的4张图,红色的点表示是不同于上一幅图的的点,即是新创建的的点。可以看到,每次插入后最多仅有logn个点会被创建。插入是按照有序的方式插入的,比如新插入seq[2]=2,那么其应该排在第二,所以我们需要事先对seq进行排序,才能知道seq[i]的具体应该插在什么位置。

  得到这些图就可以O(logN)知道第k个数了,比如要在区间[3,4]中找k=1的数字,那么只需要根据root[2]和root[4]就可以算出,只需要在每个节点上用个计数器cnt表示该子树的节点数,具体的话不难算的,自己研究下图吧。

 //#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#include <vector>
#include <iostream>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
struct Node
{
int L, R, cnt;
}nod[N*]; //线段树上的节点
struct Seq
{
int val,idx;
bool operator < ( const Seq &t ) const{return val<t.val;}
}seq[N]; //序列
int rank[N], root[N], node_cnt; void insert(int rk,int &t,int L,int R) //每次插入,就建1棵新树
{
nod[node_cnt]=nod[t];
t=node_cnt++;
nod[t].cnt++; //此子树的叶子节点数 if(L==R) return ; //到底了。只存此子树的节点数 int mid=(L+R)>>;
if(rk<=mid) insert(rk,nod[t].L, L,mid);
else insert(rk,nod[t].R, mid+,R);
} int query(int t1,int t2,int k,int L,int R)
{
if(L==R) return R; //返回的是“有序序列”的下标
int L1=nod[t1].L, L2=nod[t2].L; //两棵树的左子树节点数量
int left=nod[L2].cnt-nod[L1].cnt; //用于判断第k大在左/右
int mid=(L+R)>>; if(k<=left) query(nod[t1].L, nod[t2].L, k, L, mid); //在左边
else query(nod[t1].R, nod[t2].R, k-left, mid+, R );
} int main()
{
//freopen("input.txt", "r", stdin);
int n, m, L, R, k;
while(~scanf("%d%d",&n,&m))
{
node_cnt=;
memset(root, , sizeof(root));
for(int i=; i<=n; i++)
{
scanf("%d",&seq[i].val);
seq[i].idx=i;
}
sort(seq+,seq+n+); //需先排序
for(int i=; i<=n; i++) //反向索引
rank[ seq[i].idx ]=i;
for(int i=; i<=n; i++) //按原序逐个插入
{
root[i]=root[i-];
insert(rank[i], root[i], , n);
}
while(m--)
{
scanf("%d%d%d",&L,&R,&k);
int idx=query(root[L-], root[R], k, , n); //两树可以同时进行
printf("%d\n", seq[idx].val);
}
}
return ;
}

AC代码

POJ 2104 K-th Number (区间第k大)的更多相关文章

  1. poj 2104 主席树(区间第k大)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 44940   Accepted: 14946 Ca ...

  2. [poj 2104]主席树+静态区间第k大

    题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...

  3. POJ 2014.K-th Number 区间第k小 (归并树)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 57543   Accepted: 19893 Ca ...

  4. HDU 2665.Kth number 区间第K小

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  5. POJ2104 K-th Number —— 区间第k小 整体二分

    题目链接:https://vjudge.net/problem/POJ-2104 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Tota ...

  6. POJ 2104:K-th Number(整体二分)

    http://poj.org/problem?id=2104 题意:给出n个数和m个询问求区间第K小. 思路:以前用主席树做过,这次学整体二分来做.整体二分在yr大佬的指点下,终于大概懂了点了.对于二 ...

  7. BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 418   Solved: 235 [ Submit][ ...

  8. POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)

    题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设 ...

  9. POJ 2104:K-th Number(主席树静态区间k大)

    题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...

  10. POJ-2104-K-th Number(区间第K大+主席树模板题)

    Description You are working for Macrohard company in data structures department. After failing your ...

随机推荐

  1. 使用 Git 命令去管理项目的版本控制(一)

    参考资料:参考  参考 声明本文是作者原创,是自己的学习笔记,仅供学习参考. 在 10.11.2Mac系统中,要显示隐藏的文件夹使用命令行: defaults write com.apple.find ...

  2. sql之临时表

    select * from (select * from tb where id<10) as B

  3. Unity2D研究院之自动生成动画、AnimationController、Prefab(一)

    http://www.xuanyusong.com/archives/3243 国庆了,回家了.时刻还是要吃一颗学习的心,在家了也要抽出时间好好学习一下.之前MOMO一直没研究过Unity2D,今天研 ...

  4. [Xcode 实际操作]七、文件与数据-(23)UI Testing系统界面测试功能的使用

    目录:[Swift]Xcode实际操作 本文将演示UI Testing系统界面测试功能的使用. 如果项目中尚未引入界面测试功能,请点击项目属性面板->[General]面板左下角的[+]图标 - ...

  5. CZGL.AliIoTClient 文档:说明

    文档目录: 说明 1. 连接阿里云物联网 2. IoT 客户端 3. 订阅Topic与响应Topic 4. 设备上报属性 4.1 上报位置信息 5. 设置设备属性 6. 设备事件上报 7. 服务调用 ...

  6. mysql 主从 binlog

    binlog: 用来记录mysql的数据更新或者潜在更新(update xxx where id=x effect row 0);文件内容存储:/var/lib/mysql mysqlbinlog - ...

  7. Django quick tutorial

    --第一部分,快速开始-- 01. Django简介

  8. [coci2015-2016 coii] torrent【树形dp 二分】

    传送门:http://www.hsin.hr/coci/archive/2015_2016/ 进去之后点最下面那个. 这道题没有想出来,可惜了,其实不难的. 题目是两个“源”的,我们先考虑单源的问题. ...

  9. CentOS Linux 搭建 SVN(CollabNet Subversion)服务器

    安装CollabNet Subversion之前必须先安装JDK1.6和python2.4 ~ 2.6 groupadd svn useradd -g svn svnuser  passwd svnu ...

  10. robot framework 在pycharm中语法无法高亮显示的,显示绿色解决办法(Robot Framework with PyCharm)

    Robot Framework with PyCharm up vote1down votefavorite 1 I am totally new to automation and trying t ...