URAL - 1989 Subpalindromes (字串hash + 線段樹區間合併)
阿新 • • 發佈:2018-12-19
題目連結:http://acm.timus.ru/problem.aspx?space=1&num=1989
題目大意:給出一個長度為n的字串S,接下來進行n次操作。操作分為修改和查詢兩種,每次修改操作給出一個整數 i 和一個字元c,表示將第 i 位的字元變成字元c;每次查詢操作給出兩個整數 j 和 k ,詢問字串S的子串S[j,j+1,j+2,...,k]是否為迴文串。
題目思路:根據迴文串的定義,我們知道一個串如果滿足左半邊的串和右半邊的串是對稱的話,這個串就是迴文串。如果不考慮修改操作,我們就可以從左到右做一次字串hash,再從右到左做一次字串hash,每次詢問的時候,自需查詢S[j,...,mid] 和 S[k,..mid]的hash值是否相同即可。現在由於有修改操作,所以我們考慮可以用線段樹來維護字串的hash值,根據字串hash的性質,在push_up的過程中,H[rt] = H[rt<<1] * P[len] + H[rt<<1|1](其中 len 為右孩子的區間長度)。知道這個之後,我們就藉助線段樹區間合併的思想,從下往上合併hash值即可。這樣就只用維護兩個線段樹,一棵代表從左到右的hash值,另一棵代表從右到左的hash值。
具體實現看程式碼:
#include <bits/stdc++.h> #define fi first #define se second #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lowbit(x) x&-x #define pb push_back #define MP make_pair #define clr(a) memset(a,0,sizeof(a)) #define _inf(a) memset(a,0x3f,sizeof(a)) #define FIN freopen("in.txt","r",stdin) #define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl; using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int>pii; const int inf = 0x3f3f3f3f; const double eps = 1e-6; const int has = 99959; const int MX = 1e5 + 5; int n, m; char str[MX], str1[MX]; ull P[MX]; struct SegTree { int l, r; ull val; SegTree operator + (const SegTree &A)const { SegTree res; res.l = l; res.r = A.r; res.val = val * P[(A.r - A.l + 1)] + A.val; return res; } } T[MX << 2], T1[MX << 2]; void push_up(int rt) { T[rt] = T[rt << 1] + T[rt << 1 | 1]; } void build(int l, int r, int rt) { T[rt].l = l; T[rt].r = r; if (l == r) { T[rt].val = str[l] - 'a' + 1; return; } int m = (l + r) >> 1; build(lson); build(rson); push_up(rt); } void update(int p, ull d, int l, int r, int rt) { if (l == r) { T[rt].val = d; return; } int m = (l + r) >> 1; if (p <= m) update(p, d, lson); else update(p, d, rson); push_up(rt); } SegTree query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return T[rt]; int m = (l + r) >> 1; if (L > m) return query(L, R, rson); else if (R <= m) return query(L, R, lson); return query(L, R, lson) + query(L, R, rson); } void push_up1(int rt) { T1[rt] = T1[rt << 1] + T1[rt << 1 | 1]; } void build1(int l, int r, int rt) { T1[rt].l = l; T1[rt].r = r; if (l == r) { T1[rt].val = str1[l] - 'a' + 1; return; } int m = (l + r) >> 1; build1(lson); build1(rson); push_up1(rt); } void update1(int p, ull d, int l, int r, int rt) { if (l == r) { T1[rt].val = d; return; } int m = (l + r) >> 1; if (p <= m) update1(p, d, lson); else update1(p, d, rson); push_up1(rt); } SegTree query1(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return T1[rt]; int m = (l + r) >> 1; if (L > m) return query1(L, R, rson); else if (R <= m) return query1(L, R, lson); return query1(L, R, lson) + query1(L, R, rson); } int main() { // FIN; P[0] = 1; for (int i = 1; i < MX; i++) P[i] = P[i - 1] * has; while (~scanf("%s", str + 1)) { n = strlen(str + 1); for (int i = 1; i <= n; i++) str1[i] = str[n - i + 1]; build(1, n, 1); build1(1, n, 1); scanf("%d", &m); char op[20], s[2]; int v, l, r; while (m--) { scanf("%s", op); if (op[0] == 'c') { scanf("%d%s", &v, s); ull d = s[0] - 'a' + 1; update(v, d, 1, n, 1); update1(n - v + 1, d, 1, n, 1); } else { scanf("%d%d", &l, &r); if (l == r) { puts("Yes"); continue; } int mid = (l + r) >> 1; int lb = l, rb = mid; if ((r - l + 1) % 2 != 0) rb--; ull cnt1 = query(lb, rb, 1, n, 1).val; lb = n - r + 1, rb = n - mid; ull cnt2 = query1(lb, rb, 1, n, 1).val; if (cnt1 == cnt2) puts("Yes"); else puts("No"); } } } return 0; }