Educational Codeforces Round 132 (Rated for Div. 2), problem: (D) Rorororobot

一个线段树板子题。

一.题意

有一个n*m的格子空间,现在你有一个机器人放在位置1,你想让他到达位置2,你每次可以向它发出向上向下向左向右四个指令,但是这个机器人他坏了,所以你每次发出指令后,他都会机械地执行你的指令k次,中途不可以暂停,这n*m的格子空间,每一列格子下面都有一定高度的格子是堵塞的,如果机器人走到堵塞的格子或者跑到墙壁外面的话,那这个机器人就会爆炸,问你能不能在机器人不爆炸的前提下给它发出指令让它从位置1走到位置2。

给到你行列,还有每列堵塞的格子有多高(因为从下往上堵),然后就是查询了,每个查询给你位置1和位置2还有每次机械执行的次数k。

二.思路

想要能够到达终止位置的话必定满足以下性质。

1.起始位置纵坐标与终止位置纵坐标之差的绝对值必须是k的整数。起始位置横坐标与终止位置横坐标之差的绝对值必须是k的整数。

2.必须能绕过他们之间最高的那列堵塞(利用线段树查询区间最大值的特性,找到哪个最大,然后二分机器人走几次k能第一次到达比最大堵塞高的位置,如果这个能到达的第一个比最大堵塞高的位置超出了墙壁,那就不行)

看到这里快要结束啦,很开心你可以点进来,如果文章对你有帮助的话,可以顺手点一下下面的小手手👍吗?你的支持是对我创作最大的鼓励 !

三.代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include<cstdio>
using namespace std;
const int N = 2e5+10;
typedef long long LL;
const int maxn=2e6+10;
int a[maxn],segMax[maxn*4];//线段树数组要开大4倍
 
void build(int cur,int L,int R) 
{//cur表示区间[L,R]的标号 
	if(L==R) segMax[cur]=a[L];
	else 
    {
		int mid=(L+R)/2;
		build(cur*2,L,mid);
		build(cur*2+1,mid+1,R);
		segMax[cur]=max(segMax[cur*2],segMax[cur*2+1]);
	}
}
 
int get_max(int cur,int L,int R,int x,int y) 
{ //查询区间[x,y]的最大值
	if(x>R||y<L) return -0x3f3f3f3f; //求最大值,此时设置返回负无穷大
	if(x<=L&&y>=R) return segMax[cur];
 
	int mid=(L+R)/2;
	return max(get_max(cur*2,L,mid,x,y),get_max(cur*2+1,mid+1,R,x,y));
}
 

void solve()
{
  int n,m;
  cin>>n>>m;
  for(int i=1;i<=m;i++)
  {
     cin>>a[i];
  }
  build(1,1,m);
  int q;
  cin>>q;
  while(q--)
  {
      LL x1,y1,x2,y2;
      LL k;
      scanf("%lld%lld%lld%lld%lld",&x1,&y1,&x2,&y2,&k);
      if(abs(x2-x1)%k!=0||abs(y2-y1)%k!=0)//性质1
      {
          puts("NO");
          continue;
      }
      LL maxx=get_max(1,1,m,min(y1,y2),max(y1,y2));//线段树查询区间最大值
      LL l=0,r=1e10;
      while(l<r)
      {
          LL mid=(l+r)>>1;
          if((LL)(mid*k+(LL)min(x1,x2))>maxx) r=mid;
          else l=mid+1;
      }
      if(r*k+min(x1,x2)>n||r*k+min(x1,x2)<=maxx)//①超出墙壁②跳不过最高堵塞
      {
          puts("NO");
          continue;
      }
      puts("YES");
  }
}
int main()
{
    int T;
    T=1;
    while(T--)
    {
        solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值