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\n");
72                 else printf("No\n");
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

posted @ 2018-10-31 21:52  悠悠呦~  阅读(433)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end