题意:给出一个字符串。有两种操作,一个是p a b,问字符串从位置a到位置b的子串是否是一个回文子串。还有一个操作 c a b,把字符串位置a的字符替换为b。
题解:由于字符串长度为1e5且问的次数也有1e5,所以暴力肯定是会超时的,然后考虑用树状数组维护字符串的hash值来解,两个操作分别用正反方向区间比对哈希值和单点改动。
#include <cstdio> #include <cstring> #include <algorithm> #define ULL unsigned long long using namespace std; const int N = 100005; int n, m, l, r, pos; char str[N], q[20], c; ULL C[N][2], Hash[N]; int lowbit(int x) { return x & (-x); } ULL Sum(int x, int y) { ULL ret = 0; while (x > 0) { ret += C[x][y]; x -= lowbit(x); } return ret; } void Add(int x, ULL d, int y) { while (x <= n) { C[x][y] += d; x += lowbit(x); } } int main() { Hash[0] = 1; for (int i = 1; i < N; i++) Hash[i] = Hash[i - 1] * 27;//都是小写字母 while (scanf("%s", str) == 1) { memset(C, 0, sizeof(C)); n = strlen(str); for (int i = 0; i < n; i++) { Add(i + 1, (str[i] - 'a') * Hash[i], 0); Add(i + 1, (str[n - i - 1] - 'a') * Hash[i], 1); } scanf("%d", &m); while (m--) { scanf("%s", q); if (q[0] == 'p') { scanf("%d%d", &l, &r); ULL h1 = (Sum(r, 0) - Sum(l - 1, 0)) * Hash[n - r]; ULL h2 = (Sum(n - l + 1, 1) - Sum(n - r, 1)) * Hash[l - 1]; if (h1 == h2) printf("Yes "); else printf("No "); } else { scanf("%d %c", &pos, &c); int x = c - str[pos - 1]; Add(pos, x * Hash[pos - 1], 0); Add(n - pos + 1, x * Hash[n - pos], 1); str[pos - 1] = c; } } } return 0; }