POJ 2104 划分树
划分树:查询区间第K大
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define clc(a,b) sizeof(a,b,sizeof(a)) 6 using namespace std; 7 const int maxn=222; 8 const int MAXN = 100010; 9 int tree[20][MAXN]; 10 int sorted[MAXN]; 11 int toleft[20][MAXN]; 12 13 void build(int l,int r,int dep) { 14 if(l==r) 15 return; 16 int mid=(l+r)>>1; 17 int same= mid-l+1; 18 for(int i=l; i<=r; i++) { 19 if(tree[dep][i]<sorted[mid]) { 20 same--; 21 } 22 } 23 int lpos=l; 24 int rpos=mid+1; 25 for(int i=l; i<=r; i++) { 26 if(tree[dep][i]<sorted[mid]) 27 tree[dep+1][lpos++]=tree[dep][i]; 28 else if(tree[dep][i]==sorted[mid]&&same>0) { 29 tree[dep+1][lpos++]=tree[dep][i]; 30 same--; 31 } else 32 tree[dep+1][rpos++]=tree[dep][i]; 33 toleft[dep][i]=toleft[dep][l-1]+lpos-l; 34 } 35 build(l,mid,dep+1); 36 build(mid+1,r,dep+1); 37 } 38 39 int query(int L,int R,int l,int r,int dep,int k) { 40 if(l==r) return tree[dep][l]; 41 int mid=(L+R)>>1; 42 int cnt=toleft[dep][r]-toleft[dep][l-1]; 43 if(cnt>=k) { 44 int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; 45 int newr=newl+cnt-1; 46 return query(L,mid,newl,newr,dep+1,k); 47 } else { 48 int newr=r+toleft[dep][R]-toleft[dep][r]; 49 int newl=newr-(r-l-cnt); 50 return query(mid+1,R,newl,newr,dep+1,k-cnt); 51 } 52 } 53 54 int main() { 55 int n,m; 56 while(scanf("%d%d",&n,&m)==2) { 57 clc(tree,0); 58 for(int i=1; i<=n; i++) { 59 scanf("%d",&tree[0][i]); 60 sorted[i]=tree[0][i]; 61 } 62 sort(sorted+1,sorted+1+n); 63 build(1,n,0); 64 int s,t,k; 65 while(m--) { 66 scanf("%d%d%d",&s,&t,&k); 67 printf("%d\n",query(1,n,s,t,0,k)); 68 } 69 } 70 return 0; 71 }
View Code
还有另外一种模板,记录比当前元素还小的元素和。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define clc(a,b) sizeof(a,b,sizeof(a)) 6 #define LL long long 7 using namespace std; 8 const int N=1e5+5; 9 int p; 10 LL sum=0; 11 int sorted[N]; //对原来集合中的元素排序后的值 12 struct node { 13 int valu[N]; //val记录第k层当前位置元素的值 14 int num[N]; //num记录元素所在区间的当前位置之前进入左孩子的个数 15 LL sum[N]; //sum记录比当前元素小的元素的和 16 } t[20]; 17 18 void build(int lft,int rht,int ind) { 19 if(lft==rht) return; 20 int mid=lft+(rht-lft)>>1; 21 int isame=mid-lft+1,same=0; 22 /* isame用来标记和中间值val_mid相等的,且分到左孩子的数的个数 23 初始时,假定当前区间[lft,rht]有mid-lft+1个和valu_mid相等。 24 先踢掉中间值小的,剩下的就是要插入到左边的 25 */ 26 for(int i=lft; i<=rht; i++) 27 if(t[ind].valu[i]<sorted[mid]) isame--; 28 int ln=lft,rn=mid+1; 29 for(int i=lft; i<=rht; i++) { 30 if(i==lft) { //初始一个子树 31 t[p].num[i]=0; 32 t[p].sum[i]=0; 33 } else { //初始区间下一个节点 34 t[p].num[i]=t[p].num[i-1]; 35 t[p].sum[i]=t[p].sum[i-1]; 36 } 37 /* 如果大于,肯定进入右孩子,否则判断是否还有相等的应该进入左孩子的, 38 没有,直接进入右孩子,否则进入左孩子,同时更新节点的sum域和num域 39 */ 40 if(t[p].valu[i]<sorted[mid]) { 41 t[p].num[i]++; 42 t[p].sum[i]+=t[p].valu[i]; 43 t[p+1].valu[ln++]=t[p].valu[i]; 44 } else if(t[p].valu[i]>sorted[mid]) 45 t[p+1].valu[rn++]=t[p].valu[i]; 46 else { 47 if(same<isame) { 48 same++; 49 t[p].num[i]++; 50 t[p].sum[i]+=t[p].valu[i]; 51 t[p+1].valu[ln++]=t[p].valu[i]; 52 } else { 53 t[p+1].valu[rn++]=t[p].valu[i]; 54 } 55 } 56 } 57 build(lft,mid,ind+1); 58 build(mid+1,rht,ind+1); 59 } 60 61 int query(int a,int b,int k,int p,int lft,int rht) { 62 if(lft==rht) return t[p].valu[a]; 63 /*到达叶子结点就找到该元素,返回 64 S 记录区间[a,b]中进入左孩子的元素的个数 65 SS 记录区间[lft,a-1]中进入左孩子的元素的个数 66 SSS 记录区间[a,b]中小于第k大的元素的值和 67 B2 表示[lft,a-1]中分到右孩子的个数 68 BB 表示[a,b]中分到右孩子的个数 69 */ 70 int s,ss,b2,bb,mid=lft+(rht-lft)/2; 71 double sss=0; 72 if(a==lft) { //端点重合的情况,单独考虑 73 s = t[p].num[b]; 74 ss = 0; 75 sss = t[p].sum[b]; 76 } else { 77 s = t[p].num[b] - t[p].num[a-1]; 78 ss = t[p].num[a-1]; 79 sss = t[p].sum[b] - t[p].sum[a-1]; 80 } 81 if(s>=k) { //进入左孩子,同时更新区间端点值。 82 a = lft + ss;// 83 b = lft + ss + s - 1; 84 return query(a, b, k, p+1, lft, mid); 85 } else { 86 bb = a - lft - ss; 87 b2 = b - a - 1 - s; 88 a = mid + bb + 1; 89 b = mid + bb + b2; 90 sum += sss; 91 return query(a,b,k-s,p+1,mid+1,rht); 92 } 93 }
View Code
转载于:https://www.cnblogs.com/ITUPC/p/5277257.html
POJ 2104 划分树相关推荐
- POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)
题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设 ...
- POJ 2104 K-th Number 划分树
题意: 查询区间第\(k\)大 分析: 之前是用主席树做的,现在学一下划分树. 学习链接 划分树的空间复杂度为\(O(nlogn)\),这点比主席树更优. #include <cstdio> ...
- 【划分树】 POJ 2104 HDU 2665 K-th Number 裸题
了解了.... #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ma ...
- ACM练级日志:可持久化线段树初级-POJ 2104
近期决定把数据结构技能树继续开发下去,学习更深入层次的三项技能:可持久化线段树.动态树.树链剖分.然后那天看了看动态树,碎了,然后就去看可持久化线段树了-- 简单地说,这玩意是一个可以保存修改的历史版 ...
- 主席树学习小结(POJ 2104)
在高中的时候就听到过主席树了,感觉非常高端,在寒假的时候 winter homework中有一题是查找区间第K大的树,当时就开始百度这种网上的博客,发现主席树看不懂,因为那个root[i],还有tx[ ...
- hdu 2665 Kth number(划分树模板)
http://acm.hdu.edu.cn/showproblem.php?pid=2665 [ poj 2104 2761 ] 改变一下输入就可以过 http://poj.org/problem? ...
- 划分树基础 —— HDU 2665 Kth number
对应 HDU 题目 :点击打开链接 Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- 【转】POJ 2104 K-th Number(2)
转自: http://huangwei.host7.meyu.net/?p=24 题意:给定序列,求出[s,t]区间内第k小的数字. 解法:线段树+归并排序+二分枚举 Whu回来后,开始好好看了下其余 ...
- 【划分树+二分】HDU 4417 Super Mario
第一次 耍划分树.. . 模板是找第k小的 #include <stdio.h> #include <string.h> #include <stdlib.h> # ...
最新文章
- 杨超越第一,Python第二
- 土壤生物和生化专业委员会暨土壤生物与土壤健康研讨会(杭州5月8-11)
- Python爬虫实战(5):模拟登录淘宝并获取所有订单
- CobarClient源码分析
- 深入理解gradle中的task
- ASP.NET Core分布式项目实战(Consent Controller Get请求逻辑实现)--学习笔记
- 什么是spring_Spring 源码第三弹!EntityResolver 是个什么鬼?
- 【算法】算法 二分查找 二分查找 查找多个相同的值
- sobel算子实现边缘检测及其c++实现及与matlab效果对比
- TypeScript系列教程--初探TypeScript
- [Altium Designer 2020 硬件设计]PCB封装库创建及3D模型添加
- 阿里代码规范pdf_5年老码农的代码规范,值得学习!
- MySQL 查询各科前三名
- Java实现P5713 【深基3.例5】洛谷团队系统
- 什么是CDN,简单了解CDN
- (授人以鱼不如授人以渔)mysql-connector-java各种版本下载地址
- c语言c 哪个好学,C语言好学吗?
- 我的世界服务器信号下面是红,适用于服务器的红石抽奖机我的世界抽奖机电路图...
- 计算机学什么怎么学会的,学电脑先学什么 新手怎么学电脑
- python爬取天猫,python如何爬取天猫店铺商品链接?