Acdream 1019 Palindrome 树状数组 + 字符串hash

Acdream 1019 Palindrome

这道题也算是卡了很久了 -  -

最近才发现有些细节没考虑到。

思路是用两颗树状数组维护HASH前缀和 (一正一反两个反向)

坑1:线段树不是MLE就是TLE

坑2:在查出两个串后  多项式的幂是不一样的(s[3] * 1331 ^ 3 + s[4] * 1331 ^ 4 + s[5] * 1331 ^ 5 和 s[3] * 1331 ^ 2+s[4] * 1331 ^ 1 + s[5] * 1331 ^ 0),

不能用除法统一幂。因为这种HASH的原理是unsiged long long 溢出  相当于取余了。

这里就要用逆元  然而我并不会。所以我们把幂小的乘以一个数让他的幂变大 -  -


/*
* this code is made by Hivoodoo
* Problem: 1019
* Verdict: Accepted
* Submission Date: 2015-10-03 13:03:06
* Time: 1336MS
* Memory: 41716KB
*/
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int MAXN = 1e6+10;

ULL xl[MAXN];
//适用于正整数
template <class T>
inline void scan_d(T &ret)
{
    char c;
    ret=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}

int n;
struct BIT
{
    inline int lowbit(int x)
    {
        return x&-x;
    }
    ULL a[MAXN],b[MAXN];
    void init()
    {
        for(int i=0; i<=n; i++)
            a[i]=b[i]=0;
    }
    void add(int pos, ULL v)
    {
        for(int i=pos; i<=n; i+=lowbit(i))
            a[i] += v;
    }
    ULL sum(int pos)
    {
        ULL ret = 0;
        for (int i=pos; i>0; i-=lowbit(i))
            ret += a[i];
        return ret;
    }
    void update(int pos,ULL v)
    {
        pos++;
        if(b[pos])
            add(pos,-b[pos]);
        add(pos,b[pos]=v);
    }
    ULL query(int a,int b)
    {
        a,b++;
        return sum(b)-sum(a);
    }
} soul[2];

char s[MAXN];
int main()
{
    int m;
    xl[0]=1;
    for(int i=1; i<MAXN-1; i++)
        xl[i]=xl[i-1]*13331;
    while(scanf("%s",s)!=EOF)
    {
        n=strlen(s);
        soul[0].init();
        soul[1].init();
        scan_d(m);
        for(int i=0,j=n-1; i<n; i++,j--)
            soul[0].update(i,xl[i]*s[i]),soul[1].update(j,xl[j]*s[i]);
        while(m--)
        {
            int a,b;
            scanf("%s",s);
            if(s[0]=='Q')
            {
                scan_d(a);
                scan_d(b);
                if(a>b)
                    swap(a,b);
                a--,b--;
                ULL ra=soul[0].query(a,b);
                ULL rb=soul[1].query(n-b-1,n-a-1);
                int d=n-b-1-a;
                if(d>0)
                    ra*=xl[d];
                else
                    rb*=xl[-d];
                if(ra==rb)
                    puts("yes");
                else
                    puts("no");
            }
            else
            {
                scan_d(a);
                scanf("%s",s);
                a--;
                soul[0].update(a,s[0]*xl[a]);
                soul[1].update(n-a-1,s[0]*xl[n-a-1]);
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值