题目链接

学习了一下主席树,感觉具体算法思路不大好讲。。

大概是先建个空线段树,然后类似于递推,每一个都在前一个“历史版本”的基础上建立一个新的“历史版本”,每个历史版本只需占用树高个空间(好神奇!)

查询时这道题是通过“历史版本”间作差解决

*另外提一下,在建立“历史版本”的过程中,是“新建”,而不是“更新”,是先copy过来原有的,再按个人需求改成自己的,所产生的一个新的“历史版本”

希望注释能有帮助

//吐槽一下,本人看kuangbin模板看得好费劲,一方面不习惯用lson[],rson[]数组搞线段树,另一方面他的update query函数都是用二分写的,看半天没理解。。。

以下是按个人习惯加了注释的代码

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#define M 100000+5
using namespace std; const int N=1e5+;
const int INF=0x3f3f3f3f; struct node
{
int l,r; //l,r分别指向左右孩子,但由于历史的错乱,二者的值未必有规律
int size; //当前历史版本里,该节点中所包含的元素个数
//p.s. 在最后一个历史版本里,size即为总元素个数n
}tr[N*];
//主席树的初始状态为一“空架子”
//每次updata都在前一“历史版本”基础上新建h个结点,共updata n次,产生了n个历史版本,每个版本占用空间为h*sizeof(one node)
int tot; //结点建立顺序|所赋标号 int n; //共n个数
int a[N]; //读入数组
int root[N];//记录a[]中每一个数对应各“历史版本”在主席树中的根结点标号
int m; //t[]中元素个数
int t[N]; //离散数组
int pos(int x)
{
return lower_bound(t+,t++m,x)-t;
}
int q; //q个询问 int build(int l,int r)
{
int rt=tot++;
tr[rt].size=;
if(l==r) return rt;
int mid=(l+r)>>;
tr[rt].l=build(l,mid);
tr[rt].r=build(mid+,r);
return rt;
} // pre_node:最近一历史,[l,r]当前所更新到的包含x的区间
// x此次更新的“终点”
// 沿途要增加的“权值”
// p.s. 1<=l<=r<=m
int updata(int pre_node,int l,int r,int x,int v)
{
int rt=tot++; //rt为新结点的标号
tr[rt]=tr[pre_node]; //先拷贝原指向当前区间的结点
tr[rt].size+=v;
// 在函数不断向下深入过程中,更新node.size
if(l==r) return rt;
int mid=(l+r)>>;
if(x<=mid) tr[rt].l=updata(tr[pre_node].l,l,mid,x,v);
else tr[rt].r=updata(tr[pre_node].r,mid+,r,x,v);
return rt;
// 在函数逐步return过程中,更新node.l|r
} // ql,qr反应的是在a[]中的下标,对应着更新到该下标时的“历史版本”
// l,r反应的是在t[]中的下标
int query(int ql,int qr,int l,int r,int k)
{
if(l==r) return l;
int diff=tr[tr[qr].l].size-tr[tr[ql].l].size;//在更新到ql位置和更新到qr位置时两个“历史版本”下左孩子的size之差
// p.s. size的大小反应较小数的多少
int mid=(l+r)>>;
if(diff>=k) return query(tr[ql].l,tr[qr].l,l,mid,k);
else return query(tr[ql].r,tr[qr].r,mid+,r,k-diff);
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
for(int i=;i<=n;i++)
scanf("%d",&a[i]),t[i]=a[i];
sort(t+,t++n);
m=unique(t+,t++n)-t-;
m++,t[m]=INF;
tot=;
root[]=build(,m);    //初始化一个空线段树
for(int i=;i<=n;i++)
{
int order=pos(a[i]);
root[i]=updata(root[i-],,m,order,);
//每次在上一次已完成的基础上新增h个结点
//从根 逐步新建结点到 a[i]在线段树上所对应的位置
//在这个逐步新建结点的过程中,要新建的结点的l,r始终满足l<=m<=r
//这些结点每一个的size都在pre_node的基础上+1
}
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",t[query(root[l-],root[r],,m,k)]);
}
}
}

poj 2104: K-th Number 【主席树】的更多相关文章

  1. 【POJ 2104】 K-th Number 主席树模板题

    达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没 ...

  2. 静态区间第k大(主席树)

    POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...

  3. poj 2104 K-th Number 主席树+超级详细解释

    poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...

  4. poj2104 k-th number 主席树入门讲解

    poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树   刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...

  5. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

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

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

  7. POJ 2104 K-th Number ( 求取区间 K 大值 || 主席树 || 离线线段树)

    题意 : 给出一个含有 N 个数的序列,然后有 M 次问询,每次问询包含 ( L, R, K ) 要求你给出 L 到 R 这个区间的第 K 大是几 分析 : 求取区间 K 大值是个经典的问题,可以使用 ...

  8. SPOJ MKTHNUM & POJ 2104 - K-th Number - [主席树模板题]

    题目链接:http://poj.org/problem?id=2104 Description You are working for Macrohard company in data struct ...

  9. poj 2104 K-th Number(主席树 视频)

    K-th Number 题意: 给你一些数,让你求一个区间内,第k大的数是多少. 题解: 主席树第一题,看的qsc视频写的,戳戳戳 学到了unique函数,他的作用是:把相邻的重复的放到后面,返回值是 ...

  10. Poj 2104 K-th Number(主席树&&整体二分)

    K-th Number Time Limit: 20000MS Memory Limit: 65536K Case Time Limit: 2000MS Description You are wor ...

随机推荐

  1. 基于MyBatis实现Dao编程

    基于MyBatis实现Dao编程 1.建立mybatis-config.xml文件 <?xml version="1.0" encoding="UTF-8" ...

  2. python两个装饰器的运算顺序

    #装饰顺序按靠近函数顺序执行,调用时由外而内,执行顺序和装饰顺序相反. def makebold(func): def wrap(): return "<i>"+fun ...

  3. (转)YAML最最基础语法

    转:https://blog.csdn.net/vincent_hbl/article/details/75411243 正如YAML所表示的YAML Ain’t Markup Language,YA ...

  4. 解决IDEA输入法输入中文候选框不显示问题

    本机环境为: 系统: win7        jdk版本:jdk1.8.0_65      idea版本:2017.2.3 解决方法:关掉idea,进入idea的安装目录找到jre64文件夹重命名为j ...

  5. Packet Tracer基本使用

    Cisco Packet Tracer基本使用 1:添加设备:路由器选择1841,交换机选择2960二层交换机,添加PC.服务器Server(End Devices) 2:添加连接:这里指以太网连接, ...

  6. ubuntu python3相关

    安装pip3 sudo apt install python3-pipsudo apt-get install python3-virtualenv sudo pip3 install virtual ...

  7. Java多线程常用写法,使用匿名内部类

    匿名内部类是基于抽象类和接口而言的. //匿名内部类(解决定义过多文件的问题,标准开发一个类就是一个文件) // new Runnable() { // @Override // public voi ...

  8. Django 前戏

    1.web应用 web应用程序是一种可以通过web访问的应用程序.程序最大的好处就是用户很容易的访问应用程序,用户只需要有浏览器即可,不需要在安装其他的软件,应用程序有两种模式C/S,B/S C/S模 ...

  9. Visual Studio中把文件夹导入工程中

    VS用到的功能还是太少,记录备忘. 有的时候需要把其他库的源码导入当前工程直接使用,而这个库是源码形式,又带很多目录的. 之前从没遇到过这种情况,自己的库目录自己新建,添加. 第三方库一般有单独的Pr ...

  10. GB/T2659-2000《世界各国和地区名称代码》

    代码 代码名称 004 阿富汗 008 阿尔巴尼亚 012 阿尔及利亚 016 美属萨摩亚 020 安道尔 024 安哥拉 660 安圭拉 010 南极洲 028 安提瓜和巴布达 032 阿根廷 05 ...