poj2014 K-th Number(静态询问区间第k大数-划分树)

本文详细介绍了如何使用划分树解决区间第k大数的问题,通过实例代码讲解了算法的具体实现过程,适用于静态询问场景。

【题意】给定N个数,M个询问,每个询问l,r,k,求[l,r]区间内第k大的数是多少。

【分析】区间第k大数,很多方法都可以做。这里是静态询问,没有修改点的值。划分树练手。

 

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<algorithm>
 5 
 6 using namespace std;
 7 
 8 #define maxn 100010
 9 
10 int len;
11 int sorted[maxn];
12 int toLeft[20][maxn],val[20][maxn];
13 void build(int d, int l, int r)
14 {
15     if (l == r)
16         return ;
17     int m = (l + r)>>1;
18     int lsame = m - l + 1;
19 
20     for (int i=l;i<=r;i++){
21         if (val[d][i] < sorted[m]){
22             lsame --;
23         }
24     }
25     int lpos = l;
26     int rpos = m + 1;
27     int same = 0;
28     for (int i=l;i<=r;i++){
29         if (i == l){
30             toLeft[d][i] = 0;
31         }else {
32             toLeft[d][i] = toLeft[d][i-1];
33         }
34         if (val[d][i] < sorted[m]){
35             toLeft[d][i]++;
36             val[d+1][lpos++] = val[d][i];
37         }else if (val[d][i] > sorted[m]){
38             val[d+1][rpos++] = val[d][i];
39         }else{
40             if (same < lsame){
41                 same++;
42                 toLeft[d][i]++;
43                 val[d+1][lpos++] = val[d][i];
44             }else{
45                 val[d+1][rpos++] = val[d][i];
46             }
47         }
48     }
49     build(d+1, l, m);
50     build(d+1, m+1, r);
51 }
52 
53 
54 int query(int L, int R, int k, int d, int l,int r)
55 {
56     /**/
57     if (l == r)
58         return val[d][l];
59     int s;//s表示[L,R]内有多少个被分到了左区间
60     int ss;//ss表示[l,L-1]有多少个被分到了左区间
61     int m = (l + r)>>1;
62     if (L == l){
63         s = toLeft[d][R];
64         ss = 0;
65     }else{
66         s = toLeft[d][R] - toLeft[d][L-1];
67         ss = toLeft[d][L-1];
68     }
69     if (s >= k){//有多余k个分到左边,显然去左儿子区间找第k个
70         return query(l+ss, l+ss+s-1,k,d+1,l,m);
71     }else{
72         return query(m+L-l-ss+1, m-l-ss+R-s+1,k-s,d+1,m+1,r);
73     }
74 }
75 int n, m;
76 int main()
77 {
78     while (scanf("%d%d",&n,&m)==2)
79     {
80         for (int i=1;i<=n;i++)
81         {
82             scanf("%d",&val[1][i]);
83             sorted[i] = val[1][i];
84         }
85         sort(sorted+1,sorted+1+n);
86         build(1,1,n);
87         while (m--)
88         {
89             int l,r,k;
90             scanf("%d%d%d",&l,&r,&k);
91             if (l > r)
92                 swap(l, r);
93             printf("%d\n",query(l,r,k,1,1,n));
94         }
95     }
96     return 0;
97 }
POJ2014

 

 

转载于:https://www.cnblogs.com/wangsouc/articles/3653083.html

已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 常见问题解答 网页打开速度慢或者打不开网页? 受到多种因素的影响,对于非会员用户我们无法提供最优质的服务。 如果您希望得到最棒的体验,请至大会员页面("右上角菜单 → 大会员")根据说明操作。 请注意:受制于国际网络的诸多不确定性,我们无法对任何服务的可靠性做出任何保证。 如果出现了网络连接相关的问题,我们建议您先等待一段时间,之后再重试。 如果您在重试后发现问题仍然存在,请联系我们,并说明网络问题持续的时间。 图片下载后无法找到? 打开"右上角菜单 → 更多 → 修改下载路径",在弹出的对话框中可以看到当前图片的保存路径。 此外,由于网络因素,在保存图片之后,等待屏幕下方出现"已保存到..."后,才能在本地找到图片。 如何更改图片保存的目录? 请参见"右上角菜单 → 更多 → 修改下载路径"。 翻页不方便? 在点进某个图片后,通过在图片上向左或向右滑动,即可翻页查看下一个作品。 如何保存原图/导出动图? 长按图片/动图,在弹出的菜单中选择保存/导出即可。 输入账号密码后出现"进行人机身份验证"? 此为pixiv登陆时的验证码,请按照要求点击方框或图片。 在pxvr中注册pixiv账号后,收到验证邮件,无法访问邮件中的验证链接? 请复制邮件中的链接,打开pxvr中的"右上角菜单 → 输入地址"进行访问。 能否自动将页面内容翻译为汉语? 很抱歉,pxvr暂不提供语言翻译服务。 图片下载类型是否可以选择? 能否批量下载/批量管理下载? 已支持批量下载多图作品中的所有原图:找到一个多图作品,进入详情页面后,点击图片进入多图浏览模式,长按任意一张图片即可看到批量下载选项。 关于上述其他功能,我们...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值