现在的位置: 首页 > 综合 > 正文

bunoj 36907 Subpalindromes

2019年02月09日 ⁄ 综合 ⁄ 共 2414字 ⁄ 字号 评论关闭

这道题比赛的时候连读的机会的没有。

但是看了题目表示秒出想法。字符串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;
}

【上篇】
【下篇】

抱歉!评论已关闭.