主席树----POJ 2104(主席树裸题)(转)
首先来介绍一下我们需求:给你n个数,多次问你某个区间内的第k小是哪个数
主席树:
主席树的全名应该是 函数式版本的线段树。加上附带的一堆 technology。。
。。总之由于原名字太长了,而且 “主席” 两个字念起来冷艳高贵,以后全部称之为主席树好了。。
主席树的主体是线段树,准确的说,是很多棵线段树,存的是一段数字区间出现次数(所以要先离散化可能出现的数字)。举个例子,假设我每次都要求整个序列内的第 k 小,那么对整个序列构造一个线段树,然后在线段树上不断找第 k 小在当前数字区间的左半部分还是右半部分。这个操作和平衡树的 Rank 操作一样,只是这里将离散的数字搞成了连续的数字。
先假设没有修改操作:
对于每个前缀 S1…i,保存这样一个线段树 Ti,组成主席树。这样不是会 MLE 么?最后再讲。
注意,这个线段树对一条线段,保存的是这个数字区间的出现次数,所以是可以互相加减的!还有,由于每棵线段树都要保存同样的数字,所以它们的大小、形态也都是一样的!这实在是两个非常好的性质,是平衡树所不具备的。
对于询问 (i,j),我只要拿出 Tj 和 Ti-1,对每个节点相减就可以了。说的通俗一点,询问 i..j 区间中,一个数字区间的出现次数时,就是这些数字在 Tj 中出现的次数减去在 Ti-1 中出现的次数。
由于每棵线段树的大小形态都是一样的,而且初始值全都是 0,那每个线段树都初始化不是太浪费了?所以一开始不用建树。
然后是在某棵树上修改一个数字,由于和其他树相关联,所以不能在原来的树上改,必须弄个新的出来。难道要弄一棵新树?不是的,由于一个数字的更改只影响了一条从这个叶子节点到根的路径,所以只要只有这条路径是新的,另外都没有改变。比如对于某个节点,要往右边走,那么左边那些就不用新建,只要用个指针链到原树的此节点左边就可以了,这个步骤的前提也是线段树的形态一样。
所以根据我的理解以及网上的资料:我们首先使用vector进行离散化,每次加一个点就添一条边,并让(1,x(加入的点离散化后的大小))加一,最后模拟线段树查询就好
- #include<set>
- #include<map>
- #include<queue>
- #include<stack>
- #include<cmath>
- #include<vector>
- #include<string>
- #include<cstdio>
- #include<cstring>
- #include<iomanip>
- #include<stdlib.h>
- #include<iostream>
- #include<algorithm>
- using namespace std;
- #define eps 1E-8
- /*注意可能会有输出-0.000*/
- #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
- #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
- #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
- #define mul(a,b) (a<<b)
- #define dir(a,b) (a>>b)
- typedef long long ll;
- typedef unsigned long long ull;
- const int Inf=<<;
- const ll INF=1ll<<;
- const double Pi=acos(-1.0);
- const int Mod=1e9+;
- const int Max=1e5+;
- int root[Max],tot;//存根节点(n个根节点一定不同) 内存池
- struct node
- {
- int lef,rig,date;
- } msegtr[Max*];//开得足够大
- int a[Max];
- vector<int> vec;
- int GetId(int num)//找到离散化后原值对应的值
- {
- return lower_bound(vec.begin(),vec.end(),num)-vec.begin()+;
- }
- void Create(int sta,int enn,int &x,int y,int pos)//建树添边
- {
- msegtr[++tot]=msegtr[y];//更新这条边
- msegtr[tot].date++;
- x=tot;//增加一条边
- if(sta==enn)
- return;
- int mid=dir(sta+enn,);
- if(mid>=pos)//左子树添边
- Create(sta,mid,msegtr[x].lef,msegtr[y].lef,pos);
- else
- Create(mid+,enn,msegtr[x].rig,msegtr[y].rig,pos);
- return;
- }
- int Query(int sta,int enn,int x,int y,int k)//查询区间k大,因为满足区间减法
- {
- if(sta==enn)
- {
- return sta;
- }
- int mid=dir(sta+enn,);
- int sum=msegtr[msegtr[y].lef].date-msegtr[msegtr[x].lef].date;//左孩子区间的差
- if(sum>=k)
- return Query(sta,mid,msegtr[x].lef,msegtr[y].lef,k);
- else
- return Query(mid+,enn,msegtr[x].rig,msegtr[y].rig,k-sum);
- }
- int main()
- {
- int n,m,t;
- while(~scanf("%d %d",&n,&m))
- {
- root[]=;
- msegtr[].lef=msegtr[].rig=msegtr[].date=;
- vec.clear();
- tot=;
- for(int i=; i<=n; ++i)
- {
- scanf("%d",&a[i]);
- vec.push_back(a[i]);
- }
- sort(vec.begin(),vec.end());//离散化
- vec.erase(unique(vec.begin(),vec.end()),vec.end());//去重
- for(int i=; i<=n; ++i)
- Create(,n,root[i],root[i-],GetId(a[i]));
- int l,r,k;
- for(int i=; i<m; ++i)
- {
- scanf("%d %d %d",&l,&r,&k);
- printf("%d\n",vec[Query(,n,root[l-],root[r],k)-]);//返回原来的数字
- }
- }
- return ;
- }
参考:http://blog.csdn.net/metalseed/article/details/8045038
主席树----POJ 2104(主席树裸题)(转)的更多相关文章
- K-th Number Poj - 2104 主席树
K-th Number Poj - 2104 主席树 题意 给你n数字,然后有m次询问,询问一段区间内的第k小的数. 解题思路 这个题是限时训练做的题,我不会,看到这个题我开始是拒绝的,虽然题意清晰简 ...
- [poj 2104]主席树+静态区间第k大
题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即 ...
- [划分树] POJ 2104 K-th Number
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 51732 Accepted: 17722 Ca ...
- K-th Number POJ - 2104 划分树
K-th Number You are working for Macrohard company in data structures department. After failing your ...
- POJ 1087 最大流裸题 + map
A Plug for UNIX Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15597 Accepted: 5308 ...
- POJ 2104 主席树模板题
#include <iostream> #include <cstdio> #include <algorithm> int const maxn = 200010 ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- POJ 2104 - 主席树 / 询问莫队+权值分块
传送门 题目大意应该都清楚. 今天看到一篇博客用分块+莫对做了这道题,直接惊呆了. 首先常规地离散化后将询问分块,对于某一询问,将莫队指针移动到指定区间,移动的同时处理权值分块的数字出现次数(单独.整 ...
- poj 2104 划分树
思路:裸的划分树 #include<iostream> #include<algorithm> #include<cstring> #include<cstd ...
随机推荐
- NoSQL-MongoDB with python
前言: MongoDB,文档存储型数据库(document store).NoSQL数据库中,它独占鳌头,碾压其他的NoSQL数据库. 使用C++开发的,性能仅次C.与redis一样,开源.高扩展.高 ...
- 【BZOJ2199】[Usaco2011 Jan]奶牛议会 2-SAT
[BZOJ2199][Usaco2011 Jan]奶牛议会 Description 由于对Farmer John的领导感到极其不悦,奶牛们退出了农场,组建了奶牛议会.议会以“每头牛 都可以获得自己想要 ...
- Viewpage实现左右无限滑动
实现逻辑参考:http://www.cnblogs.com/xinye/archive/2013/06/09/3129140.html 代码:如下 public class MainActivity ...
- 阿里云服务器 进行zookeeper集群时候的肯!
首先我本地虚拟机 部署过N次没什么问题! 擦,上了云就启动后不能正常节点之间连接和发现! 这上面有手误 擦,吧编号的2 打成22 了,这个看下日志就解决了 重点是zoo.conf 中的IP进行配置时候 ...
- an open source web server and reverse proxy
https://www.nginx.com/resources/admin-guide/ NGINX is an open source web server and reverse proxy th ...
- tfboys——tensorflow模块学习(三)
tf.estimator模块 定义在:tensorflow/python/estimator/estimator_lib.py 估算器(Estimator): 用于处理模型的高级工具. 主要模块 ex ...
- 脉冲神经网络及有监督学习算法Tempotron
接下来一段时间开启脉冲神经网络模型的探索之旅.脉冲神经网络有更强的生物学基础,尽可能地模拟生物神经元之间的连接和通信方式.其潜在能力较强,值得踏进一步探索. 构建脉冲神经网络模型,至少需要考虑三点:1 ...
- BGP Basic Knowledge
声明: 这篇文章是对网上的这几篇博客的摘录,仅供我自己以后看的时候方便,且不需要再看太多的内容, 如果大家对BGP不是很了解,建议看原博客或者直接看RFC BGP只支持基于目的地址的路由,即路 ...
- MapX小试
需MapX 控件 string layerName = "12Q3_new"; string tabFile = string.Format(@"E:\map\地图\现在 ...
- Django 项目补充知识(JSONP,前端瀑布流布局,组合搜索,多级评论)
一.JSONP 1浏览器同源策略 通过Ajax,如果在当前域名去访问其他域名时,浏览器会出现同源策略,从而阻止请求的返回 由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一 ...