URAL 1989 Subpalindromes(回文串 线段树 多项式hash)

1989. Subpalindromes

Time limit: 0.5 second

Memory limit: 64 MB

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 ≤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 ≤ in; 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 substringsj...sk is a palindrome and “No” otherwise.

Sample

input output
abcda
5
palindrome? 1 5
palindrome? 1 1
change 4 b
palindrome? 1 5
palindrome? 2 4
No
Yes
Yes
Yes

Problem Author: Mikhail Rubinchik

Problem Source: Open Ural FU Championship 2013

Tags: none  (
hide tags for unsolved problems
)

这个题目  昨天晚上 看了下半夜别人的解题报告才弄懂什么意思,原来线段树强大到无所不能。我要记下来多项式hash 定义:

对于任意一个区间L,L+1,...,R

KeyL=str[ L] +str[L+1]*K  + str[L+2]* K^2  +...str[R] * K^(R-L)

KeyR=str[R] +str[R-1]*K  + str[R-2]* K^2  +...str[L] * K^(R-L)

只要是回文串,则KeyL 与 KeyR 会相等,K为某常数。

和线段树有什么关系呢?本来以为所有叶子结点分别是多项式对应的的每一项,这样的话中间节点就可能是多项式的 子集合项。并不是我直观的理解,而是任何一个结点都满足

那种多项式形式,即 任何一个结点 都是 str【L】+ str[ L + 1 ] * k + str[ L + 2 ] * K^2…………这种形式,这也就是为什么合并的时候 假设对于keyL 右孩子 要乘以Pow【x】 ,x为 左孩子子孙个数。   另外在询问的时候还学到一个技巧, 设定一个变量 T ,这个T值很有意思,如果在询问的时候往下遍历过程中,如果没有左右孩子的交叉遍历,那么此时T ==  2 || T == 1,  只有当需要左右合并的时候 此时T == 3 ,是不是很巧妙地处理?,那么从数据结构考虑,如何表示
每个结点的 正向和逆向的双向hash 结果呢?

很明显struct  或着pair 就可以了, 而以往都是用个数组来表示结点信息,这次要研究每个结点的两个属性,那么结构体或着pair 必然性出来了吧

分析清楚了 代码就很明白了 ,细节上也一看就懂了:

/*=============================================================================
#
#      Author: liangshu - cbam
#
#      QQ : 756029571
#
#      School : 哈尔滨理工大学
#
#      Last modified: 2015-08-08 17:18
#
#     Filename: A.cpp
#
#     Description:
#        The people who are crazy enough to think they can change the world, are the ones who do !
=============================================================================*/
#

#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;

#define lson l, m, rt<<1
#define rson m + 1, r, rt<<1|1
const int k = 137;
const int maxn  = 100003;
char str1[maxn];
int Pow[maxn];
int str2[maxn];
int N, M;
struct Node{
    int keyL,keyR;
    Node():keyL(0), keyR(0){}
    Node(int x, int y):keyL(x), keyR(y){}
}node[maxn<<2];

void init(){
    for(int i = 1;i <= maxn<<2; i++){
        node[i].keyL = node[i].keyR = 0;
    }
}

void pushup(int L ,int R, int rt){
    node[rt].keyL = node[rt<<1].keyL + node[rt<<1|1].keyL*Pow[L];
    node[rt].keyR = node[rt<<1].keyR * Pow[R] + node[rt<<1|1].keyR;
}

void build (int l, int r, int rt){
    if(l == r){
        node[rt].keyL = node[rt].keyR = str2[l];return ;
    }
    int m = (l + r)>>1;
    build(lson);
    build(rson);
    pushup(m - l + 1, r - m , rt);
}

void update(int p, int val, int l, int r, int rt){
    if( l == r){
        node[rt].keyL = node[rt].keyR = val;return ;
    }
    int m = ( l + r )>>1;
    if(p <= m)update(p, val, lson);
    else update( p, val, rson );
    pushup(m - l + 1, r - m, rt);
}

Node query(int L, int R, int l, int r,int rt){
    if(L <= l && r <= R){

        return node[rt];
    }
    Node ans, ans1, ans2;
    int T = 0;
    int m = (l + r)>>1;
    if(L <= m)ans1 = query(L, R, lson),T += 1;
    if(R > m) ans2 = query(L, R, rson),T += 2;

    if( T == 1 )ans = ans1;
    else if(T == 2)ans = ans2;
    else if(T == 3){
        ans.keyL = ans1.keyL + ans2.keyL * Pow[m -max(L, l) + 1];
        ans.keyR = ans1.keyR * Pow[min(R, r) - m] + ans2.keyR;
    }
    return ans;
}

int main(){

while(~scanf("%s", str1 + 1)){
        int L = strlen(str1 + 1) ;
        Pow[0] = 1;
        for(int i = 1; i <= L; i++){
            Pow[i] = Pow[i - 1] * k;
        }
        for(int i = 1; i <= L; i++){
            str2[i] = str1[i] - 'a';
        }
      init();
        scanf("%d", &M);
        build(1, L, 1);
        for(int i = 1; i <= M; i++){
            char op[23];
            scanf("%s",op);
            if(op[0] == 'c'){
                int a;char b;
                scanf("%d %c",&a,  &b);
                update(a, b - 'a', 1, L, 1);
            }
            else {
                int a, b;
                scanf("%d%d", &a, &b);
                Node ans = query(a, b, 1, L, 1);
                bool T = ans.keyL == ans.keyR;
               if(T)printf("Yes\n");
              else printf("No\n");
            }
        }
    }
    return 0;

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-28 07:31:55

URAL 1989 Subpalindromes(回文串 线段树 多项式hash)的相关文章

Palindrome - URAL - 1297(求回文串)

题目大意:RT 分析:后缀数组求回文串,不得不说确实比较麻烦,尤其是再用线段数进行查询,需要注意的细节地方比较多,比赛实用性不高......不过练练手还是可以的. 线段数+后缀数组代码如下: =========================================================================================================================================== #include<stdio

回文串+回溯法 URAL 1635 Mnemonics and Palindromes

题目传送门 1 /* 2 题意:给出一个长为n的仅由小写英文字母组成的字符串,求它的回文串划分的元素的最小个数,并按顺序输出此划分方案 3 回文串+回溯:dp[i] 表示前i+1个字符(从0开始)最少需要划分的数量,最大值是i+1,即单个回文串: 4 之前设置ok[j][j+i] 判断从j到j+i的字符是否为回文串(注意两个for的顺序,为满足ok[j][j+i] = ok[j+1][j+i-1]) 5 最后枚举找到最优划分点,用pre[i]记录前一个位置,print函数 输出空格 6 */ 7

BZOJ 3676 [Apio2014]回文串(回文树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题目大意] 考虑一个只包含小写拉丁字母的字符串s. 我们定义s的一个子串t的"出现值"为t在s中的出现次数乘以t的长度. 求s的所有回文子串中的最大出现值. [题解] 我们对给出串建立回文树,统计每个回文串出现次数和长度,相乘取组大即可 [代码] #include <cstdio> #include <algorithm> #include

HYSBZ 3676 回文串 (回文树)

3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1680  Solved: 707 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output

HYSBZ 2565 最长双回文串 (回文树)

2565: 最长双回文串 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1377  Solved: 714 [Submit][Status][Discuss] Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同). 输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y

【XSY2715】回文串 树链剖分 回文自动机

题目描述 有一个字符串\(s\),长度为\(n\).有\(m\)个操作: \(addl ~c\):在\(s\)左边加上一个字符\(c\) \(addr~c\):在\(s\)右边加上一个字符 \(transl~l_1~r_1~l_2~r_2\):有两个\(s\)的子串\(s_1=s[l_1\ldots r_1],s_2=s[l_2\ldots r_2]\).你要把\(s_1\)变成\(s_2\).每次允许在左边加一个字符或删一个字符.要求操作次数最少.定义一个字符串是好的当且仅当这个字符串是回文串

bzoj 2124 等差子序列 树状数组维护hash+回文串

等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 1919  Solved: 713[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数. 下接T组数据,

P3649 [APIO2014]回文串(回文树)

题目描述 给你一个由小写拉丁字母组成的字符串 ss .我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 ss ,求所有回文子串中的最大存在值. 输入输出格式 输入格式: 一行,一个由小写拉丁字母(a~z)组成的非空字符串 ss . 输出格式: 输出一个整数,表示所有回文子串中的最大存在值. 输入输出样例 输入样例#1: 复制 abacaba 输出样例#1: 复制 7 输入样例#2: 复制 www 输出样例#2: 复制 4 说明 [样例解

P1872 回文串计数(回文树)

题目描述 小a虽然是一名理科生,但他常常称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名其妙的热爱,这也促使他走向了以记忆量大而闻名的生物竞赛.然而,他很快发现这并不能满足他热爱背诵的心,但是作为一名强大的OIER,他找到了这么一个方法--背诵基因序列.然而这实在是太困难了,小啊感觉有些招架不住.不过他发现,如果他能事先知道这个序列里有多少对互不相交的回文串,他或许可以找到记忆的妙法.为了进一步验证这个想法,小a决定选取一个由小写字母构成的字符串SS来实验.由于互不相关的回文串实在过多