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:
- Add the number $x$ to the substring $[l \ldots r]$ of string $s$.
- 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
标签:10,le,String,Mysterious,query,Anya,回文,ldots,string From: https://www.cnblogs.com/onlyblues/p/17764165.html