1. 程式人生 > >URAL - 1989 Subpalindromes (字串hash + 線段樹區間合併)

URAL - 1989 Subpalindromes (字串hash + 線段樹區間合併)

題目連結: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;
}