URAL 1989 Subpalindromes(线段树单点修改+字符串hash)

题意:

给出一个字符串,长度为 105 ,有m个操作 m<=104
有两种操作:
1. 询问 [l,r] 区间的子串是否回文
2. 将第 i 个字符改为 c

解析:

用字符串哈希+线段树来做这题,线段树用于查询区间的hash值。
建两棵线段树一棵维护从前向后的hash值,另外一棵维护从后向前的hash值。
那么我们判断是否回文串,就只要看正反区间的哈希值之和是否相等就行了。
至于修改就是单点更新了。

my code

#include 
#include 
#include 
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
typedef unsigned long long ll;
const int N = (int)1e5 + 10;
const int sigma_size = 33;

int n, m;
ll H[N];
char str[N], str2[N];

inline ll idx(char c) { return c - 'a' + 1; }
inline int get(int pos) { return n - pos + 1; }

void init() {
    H[0] = 1;
    for(int i = 1; i < N; i++) {
        H[i] = H[i-1] * sigma_size; 
    }
}

ll lsum[N<<2], rsum[N<<2];
void pushUp(int o, int L, int R) {
    int M = (L + R)/2;
    lsum[o] = H[R - M] * lsum[ls] + lsum[rs];
    rsum[o] = H[R - M] * rsum[ls] + rsum[rs];
}

void build(int o, int L, int R) {
    if(L == R) {
        lsum[o] = idx(str[L]);
        rsum[o] = idx(str2[L]);
        return ;
    }
    int M = (L + R) >> 1;
    build(lson);
    build(rson);
    pushUp(o, L, R);
}

void modify(int o, int L, int R, int pos, int op) {
    if(L == R) {
        if(op == -1) lsum[o] = idx(str[L]);
        else rsum[o] = idx(str2[L]);
        return ;
    }
    int M = (L + R) >> 1;
    if(pos <= M) modify(lson, pos, op);
    else modify(rson, pos, op);
    pushUp(o, L, R);
}

ll query(int o, int L, int R, int ql, int qr, int op) {
    if(ql <= L && R <= qr)
        return (op == -1) ? lsum[o] : rsum[o];
    int M = (L + R) >> 1;
    if(qr <= M) return query(lson, ql, qr, op);
    else if(ql > M) return query(rson, ql, qr, op);
    return query(lson, ql, M, op) * H[qr - M] + query(rson, M+1, qr, op);
}

int main() {
    char oper[20], c[5];
    int a, b;

    init();
    while(~scanf("%s", str+1)) {
        n = strlen(str+1);
        strcpy(str2+1, str+1);
        reverse(str2+1, str2+1+n);

        build(1, 1, n); 
        scanf("%d", &m);

        ll pre, suf;
        while(m--) {
            scanf("%s", oper);
            if(oper[0] == 'p') {
                scanf("%d%d", &a, &b);
                int mid = (a + b) >> 1;
                int flag = (a + b) & 1;
                pre = query(1, 1, n, a, mid, -1);
                suf = query(1, 1, n, get(b), get(mid+flag), 1);
                puts((pre == suf) ? "Yes" : "No");
            }else {
                scanf("%d%s", &a, c);
                str[a] = c[0];
                modify(1, 1, n, a, -1);

                str2[get(a)] = c[0];
                modify(1, 1, n, get(a), 1);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(线段树)