D. Robot Queries

D. Robot Queries

There is an infinite 2-dimensional grid. Initially, a robot stands in the point (0,0). The robot can execute four commands:

  • U — move from point (x,y) to (x,y+1);
  • D — move from point (x,y) to (x,y1);
  • L — move from point (x,y) to (x1,y);
  • R — move from point (x,y) to (x+1,y).

You are given a sequence of commands s of length n. Your task is to answer q independent queries: given four integers x, y, l and r; determine whether the robot visits the point (x,y), while executing a sequence s, but the substring from l to r is reversed (i. e. the robot performs commands in order s1s2s3sl1srsr1sr2slsr+1sr+2sn).

Input

The first line contains two integers n and q (1n,q2105) — the length of the command sequence and the number of queries, respectively.

The second line contains a string s of length n, consisting of characters U, D, L and/or R.

Then q lines follow, the i-th of them contains four integers xi, yi, li and ri (nxi,yin; 1lrn) describing the i-th query.

Output

For each query, print YES if the robot visits the point (x,y), while executing a sequence s, but the substring from l to r is reversed; otherwise print NO.

Examples

input

8 3
RDLLUURU
-1 2 1 7
0 0 3 4
0 1 7 8

output

YES
YES
NO

input

4 2
RLDU
0 0 2 2
-1 -1 2 3

output

YES
NO

input

10 6
DLUDLRULLD
-1 0 1 10
-1 -2 2 5
-4 -2 6 10
-1 0 3 9
0 1 4 7
-3 -1 5 8

output

YES
YES
YES
NO
YES
YES

Note

In the first query of the first sample, the path of the robot looks as follows:


In the second query of the first sample, the path of the robot looks as follows:


In the third query of the first sample, the path of the robot looks as follows:

 

解题思路

  定义 U 关于 xy 的偏移量为 (0,1),同理 R 的偏移量为 (1,0)D 的偏移量为 (0,1)L 的偏移量为 (1,0)

  定义 f(i)=(xi,yi) 表示从坐标 (0,0) 开始执行字符串 s 的前 i 条命令所能到达的坐标(前 ix 的偏移量的和与前 iy 的偏移量的和),容易知道可以通过 f(i1) 来得到,其中 f(0)=(0,0)。对于询问 (x,y,l,r),将 s 的区间 [l,r] 翻转得到 s,再对 sf(i),是否经过坐标 (x,y) 就等价于是否存在 i[1,n] 使得 f(i)=(x,y)。可以知道如果直接暴力模拟的话时间复杂度是 O(nq) 的,容易想到能否只用 s 求得的 f(i) 来处理每一个询问呢。

  将 s 分成以下 3 段区间来考虑:[0,l1][l,r][r+1,n]

  对于区间 [0,l1],没有受到翻转的影响,即 s[0,l1]=s[0,l1],因此只需查看 i[0,l1] 中是否存在 f(i)=(x,y)。为了快速判断这里直接开一个 std::map<std::pair<int, int>, std::vector<int>> 记录每个 f(i)=(xi,yi) 出现的位置(下标)。如果询问的 (x,y) 有记录且最小下标不超过 l1,那么在这个最小的下标处就有 f(i)=(x,y),否则无解。

  对于区间 [r+1,n],同样没有受到翻转的影响,有 s[r+1,n]=s[r+1,n]。这是因为 xi 本质上是由前 ix 的偏移量求和得到的,因此只要起点不变,无论前 i 条命令以什么顺序执行,求和得到的结果都是一样的。同理 yi。如果询问的 (x,y) 有记录且最大下标至少是 r+1,那么在这个最大的下标处就有 f(i)=(x,y),否则无解。

  对于区间 [l,r],为了方便这里定义 g(i)=(xi,yi) 表示 s[i,n]x 的偏移量的和与 y 的偏移量的和,可以通过 g(i+1) 来得到,同时有 g(i)=f(n)f(i1)。对于位置 i[l,r],可以理解成从起点 f(l1)i(l1) 步到达的坐标,这是对于 s 而言的。转换到 s 中,这 i(l1) 步的偏移量就是 g(i)g(r+1),那么这个坐标就是 f(l1)+g(i)g(r+1)。因此若存在解就等价于存在 i[l,r] 使得

f(l1)+g(i)g(r+1)=(x,y)g(i)=(x,y)f(l1)+g(r+1)f(n)f(i1)=(x,y)f(l1)+f(n)f(r)f(i1)=f(l1)+f(r)(x,y)

  为此我们只需在坐标 f(l1)+f(r)(x,y) 出现的所有下标中,二分出大于等于 l1 的最小值,然后判断是否不超过 r1 即可。

  所以我们只需求出关于 sf(i),以及出现 f(i) 的所有下标。

  AC 代码如下,时间复杂度为 O(qlogn)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

char s[N];
PII f[N];
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
string ss = "URDL";

int main() {
    int n, m;
    scanf("%d %d %s", &n, &m, s + 1);
    map<PII, vector<int>> mp;
    mp[make_pair(0, 0)].push_back(0);
    for (int i = 1; i <= n; i++) {
        f[i] = f[i - 1];
        for (int j = 0; j < 4; j++) {
            if (s[i] == ss[j]) {
                f[i].first += dx[j];
                f[i].second += dy[j];
            }
        }
        mp[f[i]].push_back(i);
    }
    while (m--) {
        int x, y, l, r;
        scanf("%d %d %d %d", &x, &y, &l, &r);
        PII t = make_pair(x, y);
        if (mp.count(t) && mp[t][0] <= l - 1) {
            printf("YES\n");
        }
        else if (mp.count(t) && mp[t].back() >= r + 1) {
            printf("YES\n");
        }
        else {
            t.first = f[l - 1].first + f[r].first - t.first;
            t.second = f[l - 1].second + f[r].second - t.second;
            if (!mp.count(t)) {
                printf("NO\n");
            }
            else {
                auto it = lower_bound(mp[t].begin(), mp[t].end(), l - 1);
                printf("%s\n", it != mp[t].end() && *it < r ? "YES" : "NO");
            }
        }
    }
    
    return 0;
}

 

参考资料

  【A~F 讲解】Educational Codeforces Round 159 (Rated for Div. 2):https://www.bilibili.com/video/BV1Kg4y1f7nX/

posted @   onlyblues  阅读(112)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2021-12-04 火车进栈
Web Analytics
点击右上角即可分享
微信分享提示