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
题意:给定一个字符串s,有两种操作,第一种操作:palindrome? l r,询问s[l] s[l+1] …s[r] 是不是回文串,如果是输出“Yes”,否则输出“No”,第二种操作:change ind val,将下标ind位置的字符改为val。
思路:如果直接暴力的做,每次求出l-r和r-l的字符串的哈希值,复杂度为O(n^2),题目时限为500ms,很显然这样会超时,所以需要一种数据结构来保存字符串的哈希值。
首先我们看看暴力做的时候的复杂度,更新值的复杂度为O(1),计算哈希值的复杂度为O(n)。所以我们需要优化的是计算哈希值的复杂度,很显然树状数组或者线段树可以解决这个问题,求值只需要O(logn)的复杂度,而更新值的复杂度也是O(logn),总复杂度就是O(nlogn),很显然这个优化方法是可行的。
代码:
#include<bits/stdc++.h>
#define LL long long
#define Max 100005
#define ULL unsigned long long
const LL mod=1e9+7;
const ULL base=131;
const LL LL_MAX=9223372036854775807;
using namespace std;
ULL c[2*Max][2],p[Max];//C[..][0]保存左到右的哈希值
//C[..][1]保存右到左的哈希值
char s[Max],opt[Max];
int len,n;
void init()
{
p[0]=1;
for(int i=1;i<Max;i++)
p[i]=p[i-1]*base;
}
int lowbit(int x)
{
return x&(-x);
}
ULL getsum(int x,int dir)
{
ULL ans=0;
for(int i=x;i>0;i-=lowbit(i))
ans+=c[i][dir];
return ans;
}
void add(int x,ULL val,int dir)
{
for(int i=x;i<=len;i+=lowbit(i)){
c[i][dir]+=val;
}
}
int main()
{
scanf("%s",s+1);
len=strlen(s+1);
init();
for(int i=1;i<=len;i++){
add(i,s[i]*p[len-i],0);
add(i,s[len-i+1]*p[len-i],1);
}
scanf("%d",&n);
while(n--){
scanf("%s",opt);
if(opt[0]=='p'){
ULL h1,h2;
int l,r;
scanf("%d%d",&l,&r);
h1=(getsum(r,0)-getsum(l-1,0))*p[l-1];
h2=(getsum(len-l+1,1)-getsum(len-r,1))*p[len-r];
/*
这里需要注意,拿abcda为例子
左到右哈希值为:
a*p^4+b*p^3+c*p^2+d*p+a
右到左的哈希值为:
a*p^4+d*p^3+c*p^2+b*p+a
如果你要求3-4是不是回文串,比较的值为:
c*p^2+d*p 与 d*p^3+c*p^2
很显然它们之间的次方不对需要乘上。
*/
if(h1==h2)
printf("Yes\n");
else
printf("No\n");
}
else{
int ind;
char val[2];
scanf("%d%s",&ind,val);
ULL t=val[0]-s[ind];
s[ind]=val[0];
add(ind,t*p[len-ind],0);
add(len-ind+1,t*p[ind-1],1);
}
}
return 0;
}