Palindrome Queries

range sum hashing
View Original
Back to String Algorithms

Implementation

C++

                                #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define F first
#define S second
#define FASTIO ios_base::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);

const int MAX = 200009;

struct FenwickTree {
    ll bit[MAX];
    int n;

    FenwickTree() {
        int n = MAX;
        this->n = n;
        memset(bit, 0, sizeof(bit));
    }
    int sum(int r,int MOD) {
        int ret = 0;
        for (; r >= 0; r = (r & (r + 1)) - 1){
            ret += bit[r];
            ret%=MOD;
        }
        return ret;
    }

    int sum(int l, int r,int MOD) {
        return (sum(r,MOD) - sum(l - 1,MOD)+MOD)%MOD;
    }

    void add(int idx, int delta,int MOD) {
        for (; idx < n; idx = idx | (idx + 1)){
            bit[idx] += delta;
            bit[idx]%=MOD;
        }
    }
    void update(int idx,int val,int MOD){
        int prevVal = sum(idx,idx,MOD);
        int delta = (val - prevVal + MOD)%MOD;
        add(idx,delta,MOD);
    }
};


ll mods[2] = {1000000007, 1000000009};
//Some back-up primes: 1072857881, 1066517951, 1040160883
ll bases[2] = {137, 281};
ll pwbase[3][MAX];

void Preprocess(){
    pwbase[0][0] = pwbase[1][0] = 1;
    for(ll i = 0; i < 2; i++){
        for(ll j = 1; j < MAX; j++){
            pwbase[i][j] = (pwbase[i][j - 1] * bases[i]) % mods[i];
        }
    }
}

struct Hashing{

    ll hsh[2][MAX];
    FenwickTree ftree[2];
    string str;

    Hashing(){}
    Hashing(string _str) {str = _str; memset(hsh, 0, sizeof(hsh)); Build();}
    void init(string _str) {str = _str; memset(hsh, 0, sizeof(hsh)); Build();}

    void Build(){
        for(ll i = str.size() - 1; i >= 0; i--){
            for(int j = 0; j < 2; j++){
                hsh[j][i] = (str[i]*pwbase[j][i]) % mods[j];
                hsh[j][i] = (hsh[j][i] + mods[j]) % mods[j];
                ftree[j].add(i, hsh[j][i],mods[j] );
            }
        }
    }
    void update(int i,char c){
        for(int j = 0; j < 2; j++){
            hsh[j][i] = (c*pwbase[j][i]) % mods[j];
            hsh[j][i] = (hsh[j][i] + mods[j]) % mods[j];
            ftree[j].update(i, hsh[j][i],mods[j] );
        }
    }
    pair<ll,ll> GetHash(ll i, ll j){
        assert(i <= j);

        ll tmp1 = ftree[0].sum(i,j,mods[0]);
        ll tmp2 = ftree[1].sum(i,j,mods[1]);
        if(tmp1 < 0) tmp1 += mods[0];
        if(tmp2 < 0) tmp2 += mods[1];
        return make_pair(tmp1, tmp2);
    }
};

Hashing hashed,reverseHashed;
int n;
bool comparePalindrom(int l,int r){

    auto h1 = hashed.GetHash(l,r);
    auto h2 = reverseHashed.GetHash(n-r-1,n-l-1);

    bool b1 = (h1.F*pwbase[0][ n-r-1 ])%mods[0] == (h2.F*pwbase[0][l])%mods[0];
    bool b2 = (h1.S*pwbase[1][ n-r-1 ])%mods[1] == (h2.S*pwbase[1][l])%mods[1];

    return b1 and b2;

}
string s,rev;
int main(){
    FASTIO;
    Preprocess();
    int q;
    cin>>n>>q;
    cin>>s;
    rev = s;
    reverse(rev.begin(),rev.end());

    hashed.init(s);
    reverseHashed.init(rev);

    while(q--){
        int t;
        cin>>t;
        if( t == 2 ){
            int l,r;
            cin>>l>>r;
            l--;r--;
            if( comparePalindrom(l,r) ) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }else{
            int k;
            char x;
            cin>>k>>x;
            k--;
            hashed.update(k,x);
            reverseHashed.update(n-k-1,x);
        }
    }
}