E - Adnan and the Burned drivers(字符串哈希,线段树)
E - Adnan and the Burned drivers
题目:
给出一个长度为1e5的字符串,有1e5次操作。
操作1:修改一个字符串里的某个字符。操作2:询问字符串的\([l, r]\)是否为回文子串。
思路:
对于一个字符串快速判断是否为回文串,可以用字符串哈希通过判断正反哈希值是否相等,在\(O(logn)\)的时间内解决该问题。但是本题有一个问题是带修,那么我们可以考虑用数据结构来维护这个带修的过程。查询哈希值的过程就可以看做是一个区间求和问题,修改字符就是单点修改问题。要注意的是,要维护一个正方向的哈希值和一个反方向的哈希值。
实现:
关于字符串哈希,用unsigned long long可以自动取模,基准数可以是131或者27。
在线段树维护区间和的时候,需要注意左移和右移。
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
typedef unsigned long long ull;
char str[N];
ull bash[N * 4];
int n, m;
ull seg1[N * 4], seg2[N * 4];
void pushup(int k, int l, int r)
{
int mid = l + r >> 1;
seg1[k] = (seg1[k << 1] * bash[r - mid] + seg1[k << 1 | 1]);
seg2[k] = (seg2[k << 1] + seg2[k << 1 | 1] * bash[mid - l + 1]);
}
void update(int k, int l, int r, int x, int val)
{
if(l == r)
{
seg1[k] = seg2[k] = val;
return;
}
int mid = l + r >> 1;
if(x <= mid)
update(k << 1, l, mid, x, val);
else
update(k << 1 | 1, mid + 1, r, x, val);
pushup(k, l, r);
}
ull query(int k, int l, int r, int ql, int qr, int q)
{
if(ql == l && qr == r)
return q == 1 ? seg1[k] : seg2[k];
int mid = l + r >> 1;
if(qr <= mid)
return query(k << 1, l, mid, ql, qr, q);
else if(mid < ql)
return query(k << 1 | 1, mid + 1, r, ql, qr, q);
else if(q == 1)
return query(k << 1, l, mid, ql, mid, q) * bash[qr - mid] + query(k << 1 | 1, mid + 1, r, mid + 1, qr, q);
else
return query(k << 1, l, mid, ql, mid, q) + bash[mid - ql + 1] * query(k << 1 | 1, mid + 1, r, mid + 1, qr, q);
}
void init()
{
bash[0] = 1;
for(int i = 1; i <= 4e5; i ++)
bash[i] = bash[i - 1] * 131;
}
void solve()
{
memset(seg1, 0, sizeof seg1);
memset(seg2, 0, sizeof seg2);
scanf("%d%d", &n, &m);
scanf("%s", str + 1);
for(int i = 1; i <= n; i ++)
update(1, 1, n, i, str[i] - 'a');
while(m --)
{
int op, x, y;
scanf("%d%d", &op, &x);
if(op == 1)
{
char p[3];
scanf("%s", p);
update(1, 1, n, x, p[0] - 'a');
}
else
{
scanf("%d", &y);
if(x == y)
puts("Adnan Wins");
else
{
int mid = x + y >> 1;
ull q, p;
if((y - x + 1) & 1) //区间长度为奇数
q = query(1, 1, n, x, mid - 1, 0), p = query(1, 1, n, mid + 1, y, 1);
else //偶数
q = query(1, 1, n, x, mid, 0), p = query(1, 1, n, mid + 1, y, 1);
if(q == p)
puts("Adnan Wins");
else
puts("ARCNCD!");
}
}
}
}
int main()
{
init();
int _;
scanf("%d", &_);
while(_--)
solve();
}