You have a string and queries of two types:
replace i’th character of the string by character a;
check if substring sj…sk is a palindrome.
Input
The first line contains a string consisting of n small English letters. The second line contains an integer m that is the number of queries (5 ≤ n, m ≤ 10 5). The next m lines contain the queries.
Each query has either form “change i a”, or “palindrome? j k”, where i, j, k are integers (1 ≤ i ≤ n; 1 ≤ j ≤ k ≤ n), and character a is a small English letter.
Output
To all second type queries, you should output “Yes” on a single line if substring s j… s k is a palindrome and “No” otherwise.
Example
input output
abcda
5
palindrome? 1 5
palindrome? 1 1
change 4 b
palindrome? 1 5
palindrome? 2 4
No
Yes
Yes
Yes
题意很简单,就是单点更新某个字符,然后询问某个区间是否为回文串。
思路:首先想到利用哈希值来判断回文串,如果左右哈希值相同就是回文串。所以这题我们使用线段树,维护这个区间的左右哈希值,最后再查询,注意最后查询的时候要记录查询到当前区间时,已经查询到的长度。因为这要作为幂值
主要就是对线段树的变形,注意这个幂值。
字符串的哈希是 Hash(str[l,r]) = str[l]+str[l+1]*B + str[l+2]*B^2 + …. + str[r]*B^(r-l);
所以字符串PushUp的时候也是记录左右的长度。
int L = tree[lson].len();
int R = tree[rson].len();
tree[k].Lv = tree[lson].Lv + tree[rson].Lv*Pow[L];
tree[k].Rv = tree[lson].Rv*Pow[R] + tree[rson].Rv;
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const ull B = 1e8+7;
const int MAX = 1e5+10;
#define lson (k*2)
#define rson (k*2+1)
char str[MAX];
ull Pow[MAX];
class Node{
public:
int l,r;
ull Lv,Rv;
Node();
int len(){
return r-l+1;
}
int mid(){
return (l+r)/2;
}
};
Node tree[MAX*4];
void init(){
Pow[0] = 1;
for(int i=1;i<=(int)1e5;++i)
Pow[i] = Pow[i-1]*B;
}
void PushUp(int k){
int L = tree[lson].len();
int R = tree[rson].len();
tree[k].Lv = tree[lson].Lv + tree[rson].Lv*Pow[L];
tree[k].Rv = tree[lson].Rv*Pow[R] + tree[rson].Rv;
}
void Build(int L,int R,int k){
tree[k].l = L;
tree[k].r = R;
if(L == R){
tree[k].Lv = (ull)str[L];
tree[k].Rv = (ull)str[L];
return;
}
int mid = (L+R)/2;
Build(L,mid,lson);
Build(mid+1,R,rson);
PushUp(k);
}
void Update(int p,int k){
if(tree[k].l == tree[k].r && tree[k].l == p){
tree[k].Lv = (ull)str[p];
tree[k].Rv = (ull)str[p];
return;
}
int mid = tree[k].mid();
if(p <= mid) Update(p,lson);
else Update(p,rson);
PushUp(k);
}
//这里要每个递归,都知道当前已经找到的区间值,所以是引用,或者指针。
ull QueryL(int L,int R,int k,int &len){
if(L <= tree[k].l && tree[k].r <= R){
ull temp = tree[k].Lv*Pow[len];
len += tree[k].len();
return temp;
}
int mid = tree[k].mid();
ull res = 0;
if(L <= mid) res += QueryL(L,R,lson,len);
if(R > mid) res += QueryL(L,R,rson,len);
return res;
}
ull QueryR(int L,int R,int k,int &len){
if(L <= tree[k].l && tree[k].r <= R){
ull temp = tree[k].Rv*Pow[len];
len += tree[k].len();
return temp;
}
int mid = tree[k].mid();
ull res = 0;
if(R > mid) res += QueryR(L,R,rson,len);
if(L <= mid) res += QueryR(L,R,lson,len);
return res;
}
int main(void){
init();
scanf("%s",str+1);
int N = strlen(str+1);
Build(1,N,1);
int Q;
scanf("%d",&Q);
char op[20];
while(Q--){
scanf("%s",op);
if(strcmp(op,"palindrome?") == 0){
int l,r;
scanf("%d%d",&l,&r);
int len = 0;
ull Lv = QueryL(l,r,1,len);
len = 0;
ull Rv = QueryR(l,r,1,len);
if(Lv == Rv)
printf("Yes\n");
else
printf("No\n");
}
else{
int op;
char ch;
scanf("%d %c",&op,&ch);
str[op] = ch;
Update(op,1);
}
}
return 0;
}
Node::Node(){
l = r = 0;
Lv = Rv = 0;
}