这道题比赛的时候连读的机会的没有。
但是看了题目表示秒出想法。字符串hash+线段树
关于字符串hash 前几天刚做过一题。就是上上篇博文 《hdu 4821 String》
如果不了解字符串hash可以去看看
http://blog.csdn.net/u010724594/article/details/37819099
与队友共勉。下次记得不要卡题。
---------------------------------------------------------------------------------------
这里重新整理一下字符串hash的段换算公式。
如果我们得到一个长度为k的字符串的hash值 和 该字符串长度为j的前缀hash值
那么该字符串尾部长度为k-j的字符串hash值就可以计算得到 hash[k]-hash[j]*p[k-j+1];
p为辅助数组。p[i]为seed累乘i遍的结果。如果 不知道seed,那去看看前前篇博文吧,连接开头有。
同理可得:如果知道字符串长度为j的hash值,字符串长度为k的hash值。那么他们凭借起来的新字符串s = s1(长度为j)+s2(长度为k);长度为j+k的hash值可计算:
hash[j+k]=hash[j]*p[k]+hash[k];
这样字符串构造成线段树后,只要知道所有叶子节点的hash值,就可以通过计算得到所有父亲节点的hash值。而单个字母的hash值就是其本身。
这样我们维护两个线段树。一个是从左到右计算hash值另一个是从右到左计算hash值。查询的时候判断下两个字段的hash是否相等就能判断是否为回文串了。
代码如下:
#include<algorithm> #include<cstdio> #include<cstring> #include<map> #include<set> #include<stack> #include<queue> #include<cmath> #include<iostream> using namespace std; typedef long long LL; const int MAX = 1e5+10; const int seed = 1331; const LL MOD = 1e9+7;//虽然用了long long 但还是怕溢出 LL pl[MAX<<2] , pr[MAX<<2] , p[MAX]; char str[MAX]; void build( int l , int r , int id ){ if( l == r ){ pl[id] = pr[id] = str[l]-'a'; return ; } int m = (l+r)>>1; build( l , m , id<<1); build( m+1 , r , id<<1|1); //pushUp(id); pl[id] = (pl[id<<1]*p[r-m]+pl[id<<1|1])%MOD;//从左到右计算 pr[id] = (pr[id<<1]+pr[id<<1|1]*p[m-l+1])%MOD;//从右到左计算 } void upDate( int i , char x , int l , int r , int id ){ if( l == r ){ pl[id] = pr[id] = x-'a'; return ; } int m = ( l+r )>>1; if( i<= m ) upDate(i,x,l,m,id<<1); else upDate(i,x,m+1,r,id<<1|1); pl[id] = (pl[id<<1]*p[r-m]+pl[id<<1|1])%MOD; pr[id] = (pr[id<<1]+pr[id<<1|1]*p[m-l+1])%MOD; } LL query_l( int L , int R , int l , int r , int id ){ if( L == l && r == R ){ return pl[id]; } LL ret = 0; int m = ( l+r ) >>1 ; if( R <= m ) ret = query_l(L,R,l,m,id<<1); else if( L > m ) ret = query_l(L,R,m+1,r,id<<1|1); else ret = query_l(L,m,l,m,id<<1)*p[R-m]%MOD+query_l(m+1,R,m+1,r,id<<1|1); return ret%MOD; } LL query_r( int L , int R , int l , int r , int id ){ if( L <= l && r <= R ){ return pr[id]; } LL ret = 0; int m = ( l+r ) >>1 ; if( R <= m ) ret = query_r(L,R,l,m,id<<1); else if( L > m ) ret = query_r(L,R,m+1,r,id<<1|1); else ret = query_r(L,m,l,m,id<<1)+query_r(m+1,R,m+1,r,id<<1|1)*p[m-L+1]%MOD; return ret%MOD; } int main(){ p[0] = 1; for(int i = 1 ; i <MAX; i ++ ) p[i]=p[i-1]*seed%MOD; while(~scanf("%s" , str )){ int len = strlen(str); int n;scanf("%d",&n); build(0,len-1,1); while(n--){ char command[100];scanf("%s",command); if( strcmp(command , "palindrome?") == 0 ){ int L , R;scanf("%d%d",&L,&R); LL ret1 = query_l(L-1,R-1,0,len-1,1), ret2 = query_r(L-1,R-1,0,len-1,1); //cout<<ret1<<" "<<ret2<<endl; puts(ret1==ret2?"Yes":"No"); }else{ char x[2] ; int i ; scanf("%d%s" , &i,x); upDate(i-1,x[0],0,len-1,1); } } } return 0; }