URAL 1989 (树状数组维护哈希值 判断 字符串回文)

Subpalindromes

You have a string and queries of two types:

  1. replace i’th character of the string by character a;
  2. check if substring sj...sk is a palindrome.

Input

The first line contains a string consisting of n small English letters. The second line contains an integer m that is the number of queries (5 ≤ nm ≤ 10 5). The next m lines contain the queries. 
Each query has either form “change i a”, or “palindrome? j k”, whereijk are integers (1 ≤ i ≤ n; 1 ≤ j ≤ k ≤ n), and character a is a small English letter.

Output

To all second type queries, you should output “Yes” on a single line if substring s j... s k is a palindrome and “No” otherwise.

Example

inputoutput
abcda
5
palindrome? 1 5
palindrome? 1 1
change 4 b
palindrome? 1 5
palindrome? 2 4
No
Yes
Yes
Yes

 

题意:给一个字符串,n次操作,每次操作是  查询 区间[l,r] 的字符串是否是回文,或 改变一个位置的字符。

思路:利用树状数组维护  正反字符串的哈希值,每一次都判断查询区间的  正反是的哈希值是否相等——以此判断是否回文

AC代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define INT(t) int t; scanf("%d",&t)
#define LLI(t) LL t; scanf("%I64d",&t)

using namespace std;

const int maxn = 1e5 + 10;
const int p = 27;
typedef unsigned long long ull;

ull c[maxn][2];
ull harsh[maxn];
int lenn;

#define lowbit(x) ((x) & (-x))
void update(int i,int flag,ull value){
    while(i <= lenn){
        c[i][flag] += value;
        i += lowbit(i);
    }
}

ull sum(int i,int flag){
    ull tmp = 0;
    while(i){
        tmp += c[i][flag];
        i -= lowbit(i);
    }
    return tmp;
}

int main()
{
    char str[maxn];
    harsh[0] = 1;
    for(int i = 1;i <= maxn;i ++)
        harsh[i] = harsh[i - 1] * p;
    while(~scanf("%s",str + 1)){
        clr(c,0);
        lenn = strlen(str + 1);
        for(int i = 1;i <= lenn;i ++){
            update(i,0,(str[i] - 'a') * harsh[i]);
            update(i,1,(str[lenn - i + 1] - 'a') * harsh[i]);
        }
        int n; scanf("%d",&n);
        char t[20];
        while(n --){
            scanf("%s",t);
            if(t[0] == 'p'){
                int a,b; scanf("%d%d",&a,&b);
                ull x = (sum(b,0) - sum(a - 1,0)) * harsh[lenn - b + 1];        /// 乘以 harsh[] 为了是两字符串到达同一水平程度,再比较
                ull y = (sum(lenn - a + 1,1) - sum(lenn - b,1)) * harsh[a];     /// 最低限是 harsh[lenn - b + 1] 和 harsh[a] ,也可以同时在 +1,+2(差别也就是再同时多乘以一个27或27^2)
                if(x == y){
                    puts("Yes");
                }
                else{
                    puts("No");
                }
            }
            else{
                int a; char b; scanf("%d %c",&a,&b);
                int x = b - str[a];
                update(a,0,x * harsh[a]);
                update(lenn - a + 1,1,x * harsh[lenn - a + 1]);
                str[a] = b;
            }
        }
    }
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值