码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-08 18:22:03      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:acm   算法   编程   ural   

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 kn), 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



这个题目  昨天晚上 看了下半夜别人的解题报告才弄懂什么意思,原来线段树强大到无所不能。我要记下来多项式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;

}


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

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

标签:acm   算法   编程   ural   

原文地址:http://blog.csdn.net/lsgqjh/article/details/47359757

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!