查询某区间内最靠右的不超过k的数

为了回答这个询问, 我们需要一棵存储RMQ的线段树。 现在考虑, 把询问的区间分成了O(log
n)个节点所表示的区间之后,通过比较区间最小值与k的大小关系,立即可以判定某区间内
是否有满足条件的数。在这些区间内选择一个最靠右的,然后如果它的右儿子存在满足条件
的数,则在右儿子中查找,否则在左儿子中查找。时间复杂度当然是O(log n)。实际实现也

不用像上面说的一样分为两步,一步就够了

伪代码如下:

function find_rightmost (v, l, r, k)
if [l,r]和[v.l,v.r]没有交集
退出
end if
if (v.value > k)
返回此区间内无解
end if
if (v是叶子)
返回v
end if
if (find_rightmost(v.rch, l, r, k) 返回的不是无解)
返回 find_rightmost(v.rch, l, r, k)
else
返回 find_rightmost(v.lch, l, r, k)
end if
end function

我的代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 200001; // 区间范围
struct
{
int l, r, m; // l 左断电,r 右端点,m 为该区间的最大分数
} nod[MAXN*4];
int a[MAXN],k;
void creat(int t, int l, int r)
{
nod[t].l = l, nod[t].r = r;
if(l == r) // 叶子节点
{
nod[t].m = a[l];
return; //递归出口
}
int m = (l+r) / 2;
creat(t*2, l, m), creat(t*2+1, m+1, r); // 左孩子
nod[t].m = min(nod[t*2].m, nod[t*2+1].m); // 右孩子
}
void debug(int t)
{
    printf("%d",nod[t].m);
  if(nod[t].l==nod[t].r)
   {
     return;
   }
   debug(t*2);debug(t*2+1);
   printf("\n");
}
void update(int t, int n, int v) // 把n 点的值更新为v
{
if(nod[t].l == nod[t].r && nod[t].l == n)
{
nod[t].m = v;
return;
}
if(n <= nod[t*2].r) update(t*2, n, v);
else update(t*2+1, n, v);
nod[t].m = min(nod[t*2].m, nod[t*2+1].m);
}
int query(int t, int l, int r)
{
    int s;
if(nod[t].l>r||nod[t].r<l){return -1;}
if(nod[t].m>k){return -1;}
if(nod[t].l == nod[t].r){return nod[t].m;}
  int dd=0;
  dd=query(t*2+1,l,r);
  if(dd!=-1)
  s=dd;
  else
  s=query(t*2, l, r);
return s;
}
int main()
{
int n, m, i, x1, x2;
while(scanf("%d%d", &n, &m) != EOF)
{
for(i = 1; i <= n; i++) scanf("%d", &a[i]);
creat(1, 1, n); // 根节点标号为1,区间为【1,n】
//debug(1);
while(m--)
{
scanf("%d%d%d",&x1, &x2,&k);
printf("%d\n", query(1,x1,x2)); // 查询
}
}
return 0;
}


某些时候,在一些题目中我们需要涉及到变化的“区间”:一开始数轴上有一些相连的线
段,你每次可以查询某个点位于哪个线段,以及合并两个相邻线段,或者把某个线段一分为
二。对于这样的问题,我们可以看成是线段的端点处都是1,别的地方都是0。则“查找点位
于哪个线段”转化为“查找某点左侧区间的最右不小于1的数”以及“查找某点右侧区间的最左
不小于1的数”;而线段合并和分离分别就是查找到某个位置,然后把1改成0,或0改成1。查
找某个位置是第几条线段,可以统计某位置左侧区间的数字和。
可见,通过模型的转化,有相当多的问题都可以用线段树来解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值