D. Rorororobot(线段树寻找区间最大值)

该编程问题涉及一个由n行m列组成的网格,机器人会按照指令移动,但每次会执行K次。目标是判断能否通过发送命令让机器人从起点到达终点,同时考虑网格中的封锁区域和命令的重复执行。解决方案包括构建树状数组以快速查询最大封锁单元,并检查坐标差是否为k的倍数。
摘要由CSDN通过智能技术生成

Problem - 1709D - Codeforces

 

有一个网格,由n行和m列组成。行的编号是从1到n,从下到上。列从左至右编号为1至m。第i列的底部ai单元被封锁(第1,2,...,ai行的单元),其余n-ai单元没有被封锁。

一个机器人正在穿越这个网格。你可以向它发出指令--向上、向右、向下或向左移动。如果机器人试图移动到被封锁的单元或网格外,它就会爆炸。

然而,机器人是坏的--它对每个收到的命令都要执行K次。因此,如果你告诉它向上移动,例如,它将向上移动k次(k个单元)。在机器人执行当前的命令时,你不能向它发送命令。

你会被问到关于机器人的q个问题。你能给机器人发送任意数量的命令(可能是零),使它从起始单元到达终点单元,并考虑到它执行了每条命令的k次?

机器人必须在终点单元停下来。如果它在执行命令时访问了终点单元,则不算数。

输入
第一行包含两个整数n和m(1≤n≤109;1≤m≤2⋅105)--网格的行数和列数。

第二行包含m个整数a1,a2,...,am(0≤ai≤n)--第i列底部被封锁的单元格的数量。

第三行包含一个整数q(1≤q≤2⋅105)--查询的数量。

接下来的q行各包含五个整数xs,ys,xf,yf和k(a[ys]<xs≤n;1≤ys≤m;a[yf]<xf≤n;1≤yf≤m;1≤k≤109)--开始单元的行和列,结束单元的行和列以及每个你命令被执行的次数。每个查询的开始和结束单元格都没有被屏蔽。

输出
对于每个查询,如果你能向机器人发送任意数量的命令(可能是零),使其从起始单元到达终点单元,给定它执行每个命令的次数为k,则打印 "YES"。否则,打印 "NO"。

例子
输入复制
11 10
9 0 0 10 3 4 8 11 10 8
6
1 2 1 3 1
1 2 1 3 2
4 3 4 5 2
5 3 11 5 3
5 3 11 5 2
11 9 9 10 1
输出拷贝

拒绝

没有

题解:

如果想要起点可以到终点,首先肯定要保证,横坐标差值与纵坐标差值都是k的倍数,

其次我们知道,有些点我们是去不了的,所以我们应该找到起点与终点之间,最大的封锁单元是多少,看看起点最多可以往上走到哪,如果小于最大封锁单元说明也走不到终点

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
#include<string>
#include<map>
#define int long long
using namespace std;
typedef pair<int,int> PII;
int n,m;
struct node
{
	int l,r,mx;
}tre[1000060];
int a[200050];
void pushup(int root)
{
	tre[root].mx = max(tre[2*root].mx,tre[2*root+1].mx);
}
void build(int root,int l,int r)
{
	tre[root] = {l,r,0};
	if(l == r)
	{
		tre[root].mx = a[l];
		return ;
	}
	int mid = (l+r)/2;
	build(root*2,l,mid);
	build(root*2+1,mid+1,r);
	pushup(root);
}
int query(int rt,int l,int r)
{
	if(tre[rt].l >= l&&tre[rt].r <= r)
	return tre[rt].mx;
	int mid = (tre[rt].l + tre[rt].r)/2;
	int s = 0;
	if(mid >= l)
	{
		s = query(2*rt,l,r);
	}
	if(mid < r)
	s = max(s,query(2*rt+1,l,r));
	return s;
}

void solve()
{
	cin >> n >> m;
	for(int i = 1;i <= m;i++)
	cin >> a[i];
	build(1,1,m);
	int q;
	cin >> q;
	while(q--)
	{
		int x1,y1,x2,y2,k;
		cin >> x1 >> y1 >>x2 >>y2 >>k;
		int f = 1;
		if(abs(y1-y2)%k)
		f = 0;
		if(abs(x1-x2)%k)
		f = 0;
		int mx = query(1,min(y1,y2),max(y1,y2));
		int u = (n-x1)/k*k + x1;
		if(mx >= u)
		f = 0;
		if(f)
		cout<<"YES\n";
		else
		cout<<"NO\n";
	}
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
    int t = 1;
//    cin >> t;
    while(t--)
    {
        solve();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值