主席树学习小结(POJ 2104)
在高中的时候就听到过主席树了,感觉非常高端,在寒假的时候 winter homework中有一题是查找区间第K大的树,当时就开始百度这种网上的博客,发现主席树看不懂,因为那个root[i],还有tx[x].l与tx[x].r是什么意思没有搞懂,所以那时候那题用了划分树的思想,最近有幸看到一篇博客,然后博主推荐了一个up主的视屏讲解,最后终于弄懂了。
Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 64247 | Accepted: 22601 | |
Case Time Limit: 2000MS |
Description
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
Hint
Source
划分树模板
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100010
using namespace std;
int tree[20][MAXN],b[MAXN],p[20][MAXN];
void build(int l,int r,int dep)
{if(l==r) return;int mid=(l+r)>>1,same=mid-l+1;for(int i=l;i<=r;i++)if(tree[dep][i]<b[mid]) same--;int lpos=l,rpos=mid+1;for(int i=l;i<=r;i++){if(tree[dep][i]<b[mid]) tree[dep+1][lpos++]=tree[dep][i];else if(tree[dep][i]==b[mid]&&same>0) {tree[dep+1][lpos++]=tree[dep][i];same--;}else tree[dep+1][rpos++]=tree[dep][i];p[dep][i]=p[dep][l-1]+lpos-l;} build(l,mid,dep+1);build(mid+1,r,dep+1);
}
int query(int L,int R,int l,int r,int dep,int k)
{if(l==r) return tree[dep][l];int mid=(L+R)>>1;int cnt=p[dep][r]-p[dep][l-1];if(cnt>=k){int newl=L+p[dep][l-1]-p[dep][L-1],newr=newl+cnt-1;return query(L,mid,newl,newr,dep+1,k);}else{int newr=r+p[dep][R]-p[dep][r],newl=newr-(r-l-cnt);return query(mid+1,R,newl,newr,dep+1,k-cnt);}
}
int main(){int n,m;scanf("%d%d",&n,&m);for (int i = 1 ; i <= n; ++i){scanf("%d",&tree[0][i]);b[i] = tree[0][i];}sort(b+1,b+1+n);build(1,n,0);while(m--){int nl,nr,k;scanf("%d%d%d",&nl,&nr,&k);printf("%d\n",query(1,n,nl,nr,0,k));}return 0;
}
主席树模板
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+6;
int n,m,cnt,root[maxn],a[maxn],x,y,k;struct node{int l,r,sum;
}T[maxn*40];vector<int> v;
int getid(int x)
{return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}//离散化处理void update(int l,int r,int &x,int y,int pos)
{T[++cnt]=T[y],T[cnt].sum++,x=cnt;if(l==r) return;int mid=(l+r)/2;if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);else update(mid+1,r,T[x].r,T[y].r,pos);
} int query(int l,int r,int x,int y,int k)
{if(l==r) return l;int mid=(l+r)/2;int sum=T[T[y].l].sum-T[T[x].l].sum;//左区间中数的个数是否大于k,if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.push_back(a[i]);sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],getid(a[i]));for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&k);printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]); //前缀和的思想(y,x-1)}
}
可以先看一下up主连接:主席树
root[i]表示1-i所形成的的线段树起始的在T【】中的起始位置
T【x】.l表示左子树的位置
T【x】.r表示右子树的位置
通过l,r,pos的关系,划分是左边还是右边(及它是第几大的。和划分树的思想类似)
转载于:https://www.cnblogs.com/The-Pines-of-Star/p/9878836.html
主席树学习小结(POJ 2104)相关推荐
- LuoguP2617 Dynamic Rankings (动态主席树学习理解)
题目地址 题目链接 题解 动态主席树的板子题.动态主席树其实和静态的有很大差别,虽然同样是n个根,但是节点并不能共用,每个根节点表示bit上的一段区间. 所以其实是个树套树的东西来着,外层是bit,内 ...
- 数据结构 - 主席树
文章目录 好文推荐 求区间第K大 [模板]可持久化线段树 1(主席树) 题目 代码 可持久化数组 [模板]可持久化数组(可持久化线段树/平衡树) 好文推荐 权值线段树.主席树学习 树状结构之主席树 求 ...
- POJ 2104 K-th Number 主席树(区间第k大)
题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...
- poj 2104: K-th Number 【主席树】
题目链接 学习了一下主席树,感觉具体算法思路不大好讲.. 大概是先建个空线段树,然后类似于递推,每一个都在前一个"历史版本"的基础上建立一个新的"历史版本",每 ...
- POJ - 2104 K-th Number(主席树)
题目链接:点击查看 题目大意:给出一个数列,然后是m次查询,每次查询闭区间[l,r]内第K大的数 题目分析:裸的主席树,暑假集训第三周的时候就听说过了这个数据结构,不过当时太懒了,而且那些主席树的问题 ...
- ACM练级日志:可持久化线段树初级-POJ 2104
近期决定把数据结构技能树继续开发下去,学习更深入层次的三项技能:可持久化线段树.动态树.树链剖分.然后那天看了看动态树,碎了,然后就去看可持久化线段树了-- 简单地说,这玩意是一个可以保存修改的历史版 ...
- POJ 2104 K-th Number 划分树
题意: 查询区间第\(k\)大 分析: 之前是用主席树做的,现在学一下划分树. 学习链接 划分树的空间复杂度为\(O(nlogn)\),这点比主席树更优. #include <cstdio> ...
- 学习笔记:可持久化线段树(主席树):静态 + 动态
学习笔记:可持久化线段树(主席树):静态 + 动态 前置知识: 线段树.线段树分享可以看:@秦淮岸.@ZYzzz.@妄想の岚がそこに 树状数组.\(BIT\)分享可以看:@T-Sherlock.Chi ...
- 算法学习:主席树(可持久化线段树)
[前置知识] 线段树 [定义] [可持久化]能够保存历史版本,方便操作区间等,减少复杂度 [主席树] 可解决的经典问题区间第k大/小 时空复杂度为O(nlogn) [模板题] [luogu 3834 ...
最新文章
- 怎样解决MySQL数据库主从复制延迟的问题
- 怎么设置matlab滑块的值,matlab - 如何根据另一个滑块更改滑块的最大值 - SO中文参考 - www.soinside.com...
- 先读懂CapsNet架构然后用TensorFlow实现,这应该是最详细的教程了
- bl小说里面有个机器人管家_丰田开发机器人管家原型机 像蝙蝠一样挂在天花板上...
- 小清新自适应宇航员404页面丢失svg错误网页源码
- Android Studio添加aar依赖
- android sdk的封装,Android封装SDK的使用
- GridView样式用代码来设置
- 2021年编程语言排行榜出炉,第一名实至名归!
- 学习装黑苹果的正确姿势(小白适用)
- 备受知名投资人青睐的Pocket Network,潜力几何?
- 腾讯和360之争之二
- [源码]UnicodeTOGB,能够将Unicode串转换成GB码,方便开发。
- PS各个工具的字母快捷键和英文全名
- W10应用商店Microsoft Store的安装
- 什么是回归问题和分类问题?机器学习知识点
- upload.aspx
- 上海交通大学计算机科学与工程系,上海交通大学计算机科学与工程系(CSE)
- 输入法与表情栏无缝切换
- java视频学习网(java教程视频网)