1989. Subpalindromes
Memory limit: 64 MB
- replace i’th character of the string by character a;
- check if substring sj...sk is a palindrome.
Input
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
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 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;
}