G. Anya and the Mysterious String

G. Anya and the Mysterious String

Anya received a string $s$ of length $n$ brought from Rome. The string $s$ consists of lowercase Latin letters and at first glance does not raise any suspicions. An instruction was attached to the string.

Start of the instruction.

A palindrome is a string that reads the same from left to right and right to left. For example, the strings "anna", "aboba", "level" are palindromes, while the strings "gorilla", "banan", "off" are not.

A substring $[l \ldots r]$ of string $s$ is a string $s_l s_{l+1} \ldots s_{r-1} s_r$. For example, the substring $[4 \ldots 6]$ of the string "generation" is the string "era".

A string is called beautiful if it does not contain a substring of length at least two that is a palindrome. For example, the strings "fox", "abcdef", and "yioy" are beautiful, while the strings "xyxx", "yikjkitrb" are not.

When an integer $x$ is added to the character $s_i$, it is replaced $x$ times with the next character in the alphabet, with "z" being replaced by "a".

When an integer $x$ is added to the substring $[l, r]$ of string $s$, it becomes the string $s_1 s_2 \ldots s_{l-1} (s_l + x) (s_{l+1} + x) \ldots (s_{r-1} + x) (s_r + x) s_{r+1} \ldots s_n$. For example, when the substring $[2, 4]$ of the string "abazaba" is added with the number $6$, the resulting string is "ahgfaba".

End of the instruction.

After reading the instruction, Anya resigned herself to the fact that she has to answer $m$ queries. The queries can be of two types:

  1. Add the number $x$ to the substring $[l \ldots r]$ of string $s$.
  2. Determine whether the substring $[l \ldots r]$ of string $s$ is beautiful.

Input

The first line contains an integer $t$ ($1 \le t \le 10^4$) - the number of test cases.

The descriptions of the test cases follow.

The first line of each test case contains two integers $n$ and $m$ ($1 \le n, m \le 2 \cdot 10^5$) - the length of the string $s$ and the number of queries.

The second line of each test case contains the string $s$ of length $n$, consisting of lowercase Latin letters.

The next $m$ lines contain the queries:

$1$ $l$ $r$ $x$ ($1 \le l \le r \le n$, $1 \le x \le 10^9$) - description of a query of the first type;
$2$ $l$ $r$ ($1 \le l \le r \le n$) - description of a query of the second type.
It is guaranteed that the sum of $n$ and the sum of $m$ over all test cases do not exceed $2 \cdot 10^5$.

Output

For each query of the second type, output "YES" if the substring $[l \ldots r]$ of string $s$ is beautiful, otherwise output "NO".

You can output "YES" and "NO" in any case (for example, the strings "yEs", "yes", "Yes", and "YES" will be recognized as positive answers).

Example

input

5
12 8
tedubcyyxopz
2 2 5
1 4 8 2
2 1 7
1 3 5 40
1 9 11 3
1 10 10 9
2 4 10
2 10 12
10 4
ubnxwwgzjt
2 4 10
2 10 10
1 6 10 8
2 7 7
11 3
hntcxfxyhtu
1 4 6 1
2 4 10
1 4 10 21
13 2
yxhlmzfhqctir
1 5 9 3
1 8 13 15
2 3
bp
1 1 2 15
1 1 2 18
1 2 2 1000000000

output

YES
NO
NO
YES
NO
YES
YES
YES

Note

In the first test case of the first test, the following happens:

  • tedubcyyxopz: the string edub is beautiful;
  • tedubcyyxopz $\to$ tedwdeaaxopz;
  • tedwdeaaxopz: the string tedwdea is not beautiful as it contains the palindrome edwde;
  • tedwdeaaxopz $\to$ terkreaaxopz;
  • terkreaaxopz $\to$ terkreaaarsz;
  • terkreaaarsz $\to$ terkreaaaasz;
  • terkreaaaasz: the string kreaaaa is not beautiful as it contains the palindrome aaaa;
  • terkreaaaasz: the string asz is beautiful.

 

解题思路

  关键的地方是要想到,对于一个长度为 $n > 1$ 的回文串 $s$,如果 $n$ 是偶数,那么其一定含有长度为 $2$ 的回文(子)串,即 $s_{\frac{n}{2}} \, s_{\frac{n}{2}+1}$。如果 $n$ 是奇数,那么其一定含有长度为 $3$ 的回文(子)串,即 $s_{\left\lceil \frac{n}{2} \right\rceil - 1} \, s_{\left\lceil \frac{n}{2} \right\rceil} \, s_{\left\lceil \frac{n}{2} \right\rceil + 1}$。

  因此要判断某个给定的区间是否含有回文串,只需关注这个区间内是否包含长度为 $2$ 的回文串或长度为 $3$ 的回文串即可。对此我们可以开两个平衡树 $\text{std::set}$ 来分别维护两种长度的回文串。对于原始的字符串,我们遍历所有长度为 $2$ 和 $3$ 的连续子串,如果是发现是长度为 $2$ 的回文串,则将其左端点(下标)存到 $\text{st}_1$,如果是长度为 $3$ 的回文串,则将其左端点存到 $\text{st}_2$。

  对于查询操作,假设询的区间是 $[l,r]$,那么只需在 $\text{st}_1$ 中二分出大于等于 $l$ 的最小下标,假设是 $x$,如果 $x < r$,则说明 $[l,r]$ 中存在回文串 $s_{x} \, s_{x+1}$。同时还需要在 $\text{st}_2$ 中二分出大于等于 $l$ 的最小下标,假设是 $x$,如果 $x < r-1$,则说明 $[l,r]$ 中存在回文串 $s_{x} \, s_{x+1} \, s_{x+2}$。如果两种情况都不满足则说明 $[l,r]$ 中不存在回文串。

  对于修改操作,为了方便这里把字符 $a \sim z$ 映射成数字 $0 \sim 25$。可以发现对区间加 $[l,r]$ 上一个数后,区间内部的回文串并不会收到影响,即原本的回文串还是回文串,只不过数值改变了而已,也不会增加新的回文串。受影响的只有 $[l,r]$ 的边界点与区间外两侧的字符串。具体点来说就是 $s_{l-1} \, s_{l}$、$s_{l-2} \, s_{l-1} \, s_{l}$、$s_{l-1} \, s_{l+1}$,以及 $s_{r} \, s_{r+1}$、$s_{r} \, s_{r+1} \, s_{r+2}$、$s_{r-1} \, s_{r+1}$ 会受到影响。因此在修改前以及修改后都要在进行相应的维护(见代码)。由于我们需要进行区间加以及单点查询(某个下标是什么值),为了方便这里用树状数组来维护差分数组。

  AC 代码如下,时间复杂度为 $O((n+m) \log{n})$:

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

typedef long long LL;

const int N = 2e5 + 10;

int n, m;
char s[N];
int tr[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for (int i = x; i <= n + 1; i += lowbit(i)) {
        tr[i] = (tr[i] + c) % 26;
    }
}

int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret = (ret + tr[i]) % 26;
    }
    return ret;
}

void solve() {
    scanf("%d %d %s", &n, &m, s + 1);
    set<int> st1({n}), st2({n});    // 避免边界情况
    memset(tr, 0, n + 10 << 2);
    for (int i = 1; i <= n; i++) {
        add(i, s[i] - 'a');
        add(i + 1, 26 - (s[i] - 'a'));
        if (i + 1 <= n && s[i] == s[i + 1]) st1.insert(i);    // 长度为2的回文串,将其左端点存下来
        if (i + 2 <= n && s[i] == s[i + 2]) st2.insert(i);    // 长度为3的回文串,将其左端点存下来
    }
    while (m--) {
        int op, l, r, c;
        scanf("%d %d %d", &op, &l, &r);
        if (op == 1) {
            if (l - 1 >= 1 && query(l) == query(l - 1)) st1.erase(l - 1);
            if (l - 2 >= 1 && query(l) == query(l - 2)) st2.erase(l - 2);
            if (l + 1 <= r && l - 1 >= 1 && query(l + 1) == query(l - 1)) st2.erase(l - 1);
            if (r + 1 <= n && query(r) == query(r + 1)) st1.erase(r);
            if (r + 2 <= n && query(r) == query(r + 2)) st2.erase(r);
            if (r - 1 >= l && r + 1 <= n && query(r - 1) == query(r + 1)) st2.erase(r - 1);
            scanf("%d", &c);
            add(l, c % 26), add(r + 1, 26 - c % 26);
            if (l - 1 >= 1 && query(l) == query(l - 1)) st1.insert(l - 1);
            if (l - 2 >= 1 && query(l) == query(l - 2)) st2.insert(l - 2);
            if (l + 1 <= r && l - 1 >= 1 && query(l + 1) == query(l - 1)) st2.insert(l - 1);
            if (r + 1 <= n && query(r) == query(r + 1)) st1.insert(r);
            if (r + 2 <= n && query(r) == query(r + 2)) st2.insert(r);
            if (r - 1 >= l && r + 1 <= n && query(r - 1) == query(r + 1)) st2.insert(r - 1);
        }
        else {
            if (*st1.lower_bound(l) < r || *st2.lower_bound(l) < r - 1) printf("NO\n");    // 区间内存在长度为2或3的回文串
            else printf("YES\n");
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 903 (Div. 3) Editorial:https://codeforces.com/blog/entry/121327

posted @ 2023-10-14 14:51  onlyblues  阅读(85)  评论(0编辑  收藏  举报
Web Analytics