URAL 1989 Subpalindromes

题意 :  给你一个长度为N的字符串   有M个操作  每个操作有两种选择 一种是询问A到B这个区间长度的字符串是否为回文串   另一种是修改位置为A的字符

解题思路:涉及到区间询问 和 点修改 很容易想到最基本的线段树去操作  只是构建有点难想   可以用多项式哈希解决   假设我现在有一个长度为5的字符串abcde

那么它的多项式哈希为 ax + bx^2 + cx^3 + dx^4 + ex^5  这边的abcde的值可以默认成0 ~ 25  x理论可取任意值  这里避免重复  可以取 25以上的值  那么我们可以在

一开始构建两棵线段树  一棵存顺序  一棵存逆序  然后询问的时候只要判断顺序的哈希值和逆序的哈希值是否相同就可以了   当然这边询问到结果后还需处理一下

因为两次的询问可能相差x^?次方  所以要把x^?乘上  比如说我现在abcde的逆序为  edcba  那么我如果询问1 3 顺序的哈希值为   ax + bx^2 + cx^3  逆序哈希值为

cx^3 + bx^4 +ax^5  所以我要给顺序的哈希值乘上x^2才能去判断   一开始取x的时候觉得取什么值都会溢出  其实这边溢出不溢出是没什么关系的。


    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<iostream>
    #include<map>
    #include<set>
    #include<queue>
    #include<list>
    #include<stack>
    #include<vector>
    #include<math.h>
    #include<stdlib.h>
    #include<time.h>
    using namespace std;
    #define ll long long
    #define mem(a) memset(a,0,sizeof(a))
    #define CLR(a, b) memset(a, b, sizeof(a))
    #define INF 0x3f3f3f
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    const int maxn = 100005;
    ll sum[2][maxn<<2];
    char s[maxn];
    ll h[maxn];
    void init(){
        h[0] = 1;
        for(int i = 1;i < maxn;i++)
            h[i] = h[i - 1] * 33;
    }
    void pushup(int rt ,int sign){
        sum[sign][rt] = sum[sign][rt<<1] + sum[sign][rt<<1|1];
    }
    void build(int l ,int r ,int rt,int sign){
        if(l == r){
            sum[sign][rt] = (s[l - 1] - 'a') * h[l];
            return;
        }
        int m = (l + r) >> 1;
        build(lson,sign);
        build(rson,sign);
        pushup(rt,sign);
    }
    void update(int pos,char val,int l,int r,int rt,int sign){
        if(l == r) {
            sum[sign][rt] = (val - 'a') * h[l];
            return;
        }
        int m = (l + r) >> 1;
        if(pos <= m) update(pos,val,lson,sign);
        else update(pos,val,rson,sign);
        pushup(rt,sign);
    }
    ll query(int L,int R,int l ,int r, int rt,int sign){
        if(L <= l && R>= r) return sum[sign][rt];
        int m = (l + r) >> 1;
        ll ans = 0;
        if(L <= m) ans += query(L,R,lson,sign);
        if(R > m) ans += query(L,R,rson,sign);
        return ans;
    }
    int main(){
        init();
        while(scanf("%s",s) != EOF){
            int n = strlen(s);
            build(1,n,1,0);
            reverse(s, s + n);
            build(1,n,1,1);
            int m;
            scanf("%d",&m);
            while(m--){
                char choose[30];
                scanf("%s",choose);
                if(choose[0] == 'p'){
                    int a,b;
                    scanf("%d%d",&a,&b);
                    ll ans1 = query(a,b,1,n,1,0);
                    ll ans2 = query(n - b + 1,n - a + 1,1,n,1,1);
                    int len = (n - b + 1) - a;
                    if(len > (b - a + 1)) len = b - a + 1;
                    if(len > 0){
                        ans1 *= h[len];
                    }
                    else{
                        len = abs((n - b + 1) - a);
                        if(len > (b - a + 1)) len = b - a + 1;
                        if(len > 0){
                            ans2 *= h[len];
                        }
                    }
                    if(ans1 == ans2) puts("Yes");
                    else puts("No");
                }
                else if(choose[0] == 'c'){
                    int pos;
                    char val;
                    scanf("%d %c",&pos,&val);
                    update(pos,val,1,n,1,0);
                    update(n - pos + 1,val,1,n,1,1);
                }
            }
        }
        return 0;
    }




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值