【URAL 1989】 Subpalindromes(线段树维护哈希)

Description


You have a string and queries of two types:
replace i’th character of the string by character a;
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 ≤ n, m ≤ 105). The next m lines contain the queries.
Each query has either form “change i a”, or “palindrome? j k”, where i, j, k 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 sj...sk is a palindrome and “No” otherwise.

Sample input

abcda
5
palindrome? 1 5
palindrome? 1 1
change 4 b
palindrome? 1 5
palindrome? 2 4

Sample onput

No
Yes
Yes
Yes

题解

使用线段树维护哈希值。
滚动哈希即rabin-karp
原hash:
\(ha[i]=ha[i-1]\times seed+s[i]\)
可以预处理出seed进位:
\(p[i]=p[i-1]\times seed\)
这样每个位置的哈希值可以直接算出。
如果要改变某个位置的字符,那么原hash值变成
\(ha[i]=p[i-1]\times ch\)
这样的hash计算无需滚动,因为计算出了进位,每一位是直接算出的。那么可以直接合并两个区间的哈希值,
即:
ha[rt]=ha[rt<<1]+ha[rt<<1|1]
改变也是单调修改,这些都是线段树的经典应用

import java.io.*;
import java.util.*;

public class Main {
    static final int N = (int)1e5+10;
    //static final long MOD=(int)1e18+7;
    static final int inf = 0x3f3f3f3f;
    static char a[]=new char[N];
    static long p[]=new long[N];
    static long ha[]=new long[N];
    static long sum[][]=new long[2][N<<2];
    static void Init(int n) {
        int seed=123;
        p[0]=1;
        for(int i=1;i<=n;i++) p[i]=(p[i-1]*seed);
    }
    static void PushUp(int rt,int flag) {
        sum[flag][rt]=(sum[flag][rt<<1]+sum[flag][rt<<1|1]);
    }
    static void Build(int rt,int l,int r,int flag) {
        if(l==r) {
              sum[flag][rt]=ha[l];
              return;
        }
        int mid=(l+r)>>1;
        Build(rt<<1,l,mid,flag);
        Build(rt<<1|1,mid+1,r,flag);
        PushUp(rt,flag);
    }
    static void update(int a,long b,int rt,int l,int r,int flag) {
        if(l==r) {
            sum[flag][rt]=b;
            return;
        }
        int mid=(l+r)>>1;
        if(a<=mid) update(a,b,rt<<1,l,mid,flag);
        if(a>mid) update(a,b,rt<<1|1,mid+1,r,flag);
        PushUp(rt,flag);
    }
    static long query(int a,int b,int rt,int l,int r,int flag) {
        if(a<=l&&r<=b) {
            return sum[flag][rt];
        }
        int mid=(l+r)>>1;
        long res=0;
        if(a<=mid) res=(res+query(a,b,rt<<1,l,mid,flag));
        if(b>mid) res=(res+query(a,b,rt<<1|1,mid+1,r,flag));
        return res;
    }
    public static void main(String[] args) {
        InputStream sysi = System.in;
        OutputStream syso = System.out;
        InputReader in = new InputReader(sysi);
        PrintWriter out = new PrintWriter(syso);
        a=in.next().toCharArray();
        int m=in.nextInt();
        int s,e,s1,e1,n=a.length;char ch;
        Init(n);
        for(int i=0;i<n;i++) ha[i+1]=((long)a[i]*p[i]);
        Build(1,1,n,0);
        char tmp;
        for(int i=0;i<n/2;i++) {
            tmp=a[i];a[i]=a[n-i-1];
            a[n-i-1]=tmp;
        }
        for(int i=0;i<n;i++) ha[i+1]=((long)a[i]*p[i]);
        Build(1,1,n,1);String str;
        while(m--!=0) {
             if(in.next().equals("palindrome?")) {
                  s=in.nextInt();e=in.nextInt();
                  long ha1=query(s,e,1,1,n,0);
                  s1=n+1-e;e1=n+1-s;
                  long ha2=query(s1,e1,1,1,n,1);
                  if(s1>s) ha1=(ha1*p[s1-s]);
                  else ha2=(ha2*p[s-s1]);
                  if(ha1==ha2) out.println("Yes");
                  else out.println("No");
             }else {
                  s=in.nextInt();str=in.next();
                  ch=str.charAt(0);
                  update(s,p[s-1]*ch,1,1,n,0);
                  update(n+1-s,p[n-s]*ch,1,1,n,1);
             }
             out.flush();
        }
        out.close();
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }
    }
}

转载于:https://www.cnblogs.com/zsyacm666666/p/7504589.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值