划分树:查询区间第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 划分树相关推荐

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

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

  2. POJ 2104 K-th Number 划分树

    题意: 查询区间第\(k\)大 分析: 之前是用主席树做的,现在学一下划分树. 学习链接 划分树的空间复杂度为\(O(nlogn)\),这点比主席树更优. #include <cstdio> ...

  3. 【划分树】 POJ 2104 HDU 2665 K-th Number 裸题

    了解了.... #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ma ...

  4. ACM练级日志:可持久化线段树初级-POJ 2104

    近期决定把数据结构技能树继续开发下去,学习更深入层次的三项技能:可持久化线段树.动态树.树链剖分.然后那天看了看动态树,碎了,然后就去看可持久化线段树了-- 简单地说,这玩意是一个可以保存修改的历史版 ...

  5. 主席树学习小结(POJ 2104)

    在高中的时候就听到过主席树了,感觉非常高端,在寒假的时候 winter homework中有一题是查找区间第K大的树,当时就开始百度这种网上的博客,发现主席树看不懂,因为那个root[i],还有tx[ ...

  6. hdu 2665 Kth number(划分树模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=2665 [ poj 2104 2761 ]  改变一下输入就可以过 http://poj.org/problem? ...

  7. 划分树基础 —— HDU 2665 Kth number

    对应 HDU 题目 :点击打开链接 Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  8. 【转】POJ 2104 K-th Number(2)

    转自: http://huangwei.host7.meyu.net/?p=24 题意:给定序列,求出[s,t]区间内第k小的数字. 解法:线段树+归并排序+二分枚举 Whu回来后,开始好好看了下其余 ...

  9. 【划分树+二分】HDU 4417 Super Mario

    第一次 耍划分树.. . 模板是找第k小的 #include <stdio.h> #include <string.h> #include <stdlib.h> # ...

最新文章

  1. 杨超越第一,Python第二
  2. 土壤生物和生化专业委员会暨土壤生物与土壤健康研讨会(杭州5月8-11)
  3. Python爬虫实战(5):模拟登录淘宝并获取所有订单
  4. CobarClient源码分析
  5. 深入理解gradle中的task
  6. ASP.NET Core分布式项目实战(Consent Controller Get请求逻辑实现)--学习笔记
  7. 什么是spring_Spring 源码第三弹!EntityResolver 是个什么鬼?
  8. 【算法】算法 二分查找 二分查找 查找多个相同的值
  9. sobel算子实现边缘检测及其c++实现及与matlab效果对比
  10. TypeScript系列教程--初探TypeScript
  11. [Altium Designer 2020 硬件设计]PCB封装库创建及3D模型添加
  12. 阿里代码规范pdf_5年老码农的代码规范,值得学习!
  13. MySQL 查询各科前三名
  14. Java实现P5713 【深基3.例5】洛谷团队系统
  15. 什么是CDN,简单了解CDN
  16. (授人以鱼不如授人以渔)mysql-connector-java各种版本下载地址
  17. c语言c 哪个好学,C语言好学吗?
  18. 我的世界服务器信号下面是红,适用于服务器的红石抽奖机我的世界抽奖机电路图...
  19. 计算机学什么怎么学会的,学电脑先学什么 新手怎么学电脑
  20. python爬取天猫,python如何爬取天猫店铺商品链接?

热门文章

  1. MNIST数据集手写数字识别(一)
  2. Java学习总结(随笔)——利用JSON解析实现网络下载
  3. MySQL数据库(九) 一一 处理重复和SQL注入
  4. php设置http请求头信息和响应头信息
  5. LVS+Keepalive+Nginx实现负载均衡
  6. android google map研究
  7. 超多的CSS3圆角渐变网页按钮
  8. Android自动化测试 monkey 工具学习3
  9. oracle数据库同步异步优劣点,ORACLE数据库异步IO介绍
  10. Python中利用*打印不同的三角形