• URAL 1989 Subpalindromes (多项式hash) +【线段树】


    <题目链接>

    <转载于 >>>  >

    题目大意:
    给你一段字符串,进行两种操作:
    1.询问[l,r]这个区间中的字符串是否是回文串;

    2.更改该字符串中对应下标的字符。

    解题分析:

    快速判断字符串是不是回文串,可以用到多项式Hash。假设一个串s,那么字串s[i, j]的Hash值就是H[i, j]=s[i]+s[i+1]*x+s[i+2]*(x^2)+...+s[j]*(x^(j-i))。由于只有小写字母,因此x取27。但是H[i, j]这会很大,我们取模就可了,可以把变量类型设为unsigned long long, 那么自动溢出就相当于模2^64了。对于不同串但是Hash相同的情况,这种情况的概率是非常小的,通常可以忽略,当然我们也可以对x取多次值,求出不同情况下的Hash值。然后我们就可以用线段树或者树状数组来维护这个和了,复杂度O(nlogn)。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define Lson rt<<1,l,mid
     7 #define Rson rt<<1|1,mid+1,r
     8 #define N 100005
     9 #define ull unsigned long long 
    10 ull f[N];
    11 char s[N];
    12 int n;
    13 struct Tree{
    14     ull lsum,rsum;    //左->右和右->左的hash值
    15 }tr[N<<2];
    16 void Pushup(int rt){    //将该区间内从左到右和从右到左的多项式hash的每一位相加
    17     tr[rt].lsum=tr[rt<<1].lsum+tr[rt<<1|1].lsum;
    18     tr[rt].rsum=tr[rt<<1].rsum+tr[rt<<1|1].rsum;
    19 }
    20 void build(int rt,int l,int r){
    21     if(l==r){
    22         tr[rt].lsum=f[l-1]*(s[l-1]-'a');     //得到hash多项式相应位置的hash值
    23         tr[rt].rsum=f[n-l]*(s[l-1]-'a');
    24         return;
    25     }
    26     int mid=(l+r)>>1;
    27     build(Lson);
    28     build(Rson);
    29     Pushup(rt);
    30 }
    31 void update(int rt,int l,int r,int pos,int num){
    32     if(l==r){
    33         tr[rt].lsum=f[l-1]*num;
    34         tr[rt].rsum=f[n-l]*num;
    35         return;
    36     }
    37     int mid=(l+r)>>1;
    38     if(pos<=mid)update(Lson,pos,num);
    39     if(pos>mid)update(Rson,pos,num);
    40     Pushup(rt);
    41 }
    42 ull lsum,rsum;
    43 void query(int rt,int l,int r,int L,int R){
    44     if(L<=l&&r<=R){
    45         lsum+=tr[rt].lsum;
    46         rsum+=tr[rt].rsum;
    47         return;
    48     }
    49     int mid=(l+r)>>1;
    50     if(L<=mid)query(Lson,L,R);
    51     if(R>mid)query(Rson,L,R);
    52 }
    53 int main(){
    54     f[0]=1;
    55     for(int i=1;i<N;i++)
    56         f[i]=f[i-1]*27;    //预处理27的1~N次方
    57     while(scanf("%s",s)!=EOF){
    58         n=strlen(s);
    59         build(1,1,n);
    60         int q;scanf("%d",&q);
    61         while(q--){
    62             scanf("%s",s);
    63             if(s[0]=='p'){
    64                 int x,y;scanf("%d%d",&x,&y);
    65                 lsum=rsum=0;
    66                 query(1,1,n,x,y);
    67                 int k1=x-1;
    68                 int k2=n-y;
    69                 if(k1>k2)rsum*=f[k1-k2];  //按照上面的计算方式,从左向右和从右向左的相同hash多项式的计算中,短区域中的每一项会比长区域少乘f[k1-k2](或f[k2-k1])次方,所以这里要讲相差的f[]乘上,再进行比较
    70                 else lsum*=f[k2-k1];
    71                 if(lsum==rsum)printf("Yes
    ");
    72                 else printf("No
    ");
    73             }
    74             else{
    75                 int x;
    76                 scanf("%d%s",&x,s);
    77                 update(1,1,n,x,s[0]-'a');
    78             }
    79         }
    80     }
    81 }

    2018-10-31

  • 相关阅读:
    2020/10/29
    2020/10/24
    2020/10/28
    2020/10/31周报
    linux shell 中判断字符串为空的正确方法
    20201107 千锤百炼软工人
    20201103 千锤百炼软工人
    20201109 千锤百炼软工人
    20201111 千锤百炼软工人
    20201105 千锤百炼软工人
  • 原文地址:https://www.cnblogs.com/00isok/p/9886163.html
Copyright © 2020-2023  润新知