input | output |
---|---|
abcda 5 palindrome? 1 5 palindrome? 1 1 change 4 b palindrome? 1 5 palindrome? 2 4 |
No Yes Yes Yes |
这个题目 昨天晚上 看了下半夜别人的解题报告才弄懂什么意思,原来线段树强大到无所不能。我要记下来多项式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)
原文地址:http://blog.csdn.net/lsgqjh/article/details/47359757