线段树查询区间回文+区间字母右移

线段树查询区间回文 + 区间字母右移

属于一道很有意思的线段树,线段树维护以下信息。

struct node{
    int l, r, ln;
    int hash1[26], hash2[26];
    int tag;
}tr[N << 2];

维护线段左右端点,线段长度, 26 26 26 个字母的哈希值,以及区间移动懒标记。

关于 h a s h 1 hash1 hash1 ,表示一个区间的正哈希值,例如 a b c d a abcda abcda h a s h 0 = p 0 + p 4 hash_0=p^0+p^4 hash0=p0+p4 , h a s h 1 = p 1 hash_1=p^1 hash1=p1 , h a s h 2 = p 2 hash_2=p^2 hash2=p2 , h a s h 3 = p 3 hash_3=p^3 hash3=p3

也就是说, h a s h i hash_i hashi 维护对应字母在当前线段自己位置的哈希值。

那么显然 ∑ i = 0 26 h a s h i × i \sum_{i=0}^{26}hash_i\times i i=026hashi×i 就是一条线段的哈希值。

只需要维护正反两种哈希即可 。

剩下就是上传和下传操作了,对于上传,想要拼接 p 0 + p 1 + p 3 p_0+p_1+p_3 p0+p1+p3 p 0 + p 1 p_0+p_1 p0+p1 ,显然右边应该再乘上 p l . l n p^{l.ln} pl.ln

对于下传,其实本质就是交换哈希值,开两个临时数组备份一下 h a s h 1 hash1 hash1 h a s h 2 hash2 hash2 ,然后移动一下哈希值即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long

string s;

int const N = 1e5 + 10;

#define lc u << 1
#define rc u << 1 | 1

int const P = 13331;
int const mod = 1e9 + 7;

int p[N];

struct node{
    int l, r, ln;
    int hash1[26], hash2[26];
    int tag;
}tr[N << 2];

void pushup(node &u, node &lson, node &rson){
    u.l = lson.l, u.r = rson.r, u.ln = lson.ln + rson.ln;
    for(int i = 0; i < 26; i ++){ 
        u.hash1[i] = (lson.hash1[i] + rson.hash1[i] * p[lson.ln] % mod) % mod;
        u.hash2[i] = (rson.hash2[i] + lson.hash2[i] * p[rson.ln] % mod) % mod;
    }
}

void pushup(int u){
    pushup(tr[u], tr[lc], tr[rc]);
}

void build(int u, int l, int r){
    tr[u].l = l, tr[u].r = r, tr[u].ln = 1, tr[u].tag = 0;
    memset(tr[u].hash1, 0, sizeof tr[u].hash1);
    memset(tr[u].hash2, 0, sizeof tr[u].hash2);
    tr[u].hash1[s[l] - 'a'] = tr[u].hash2[s[l] - 'a'] = p[0]; // can delete later
    if(l == r) return ; 
    int mid = l + r >> 1;
    build(lc, l, mid), build(rc, mid + 1, r);
    pushup(u);
}  

void pushdown(int u, int tag){
    tag %= 26;
    if(tag){
        vector<int> t1(26, 0), t2(26, 0);
        for(int i = 0; i < 26; i ++){
            t1[i] = tr[u].hash1[i];
            t2[i] = tr[u].hash2[i];
        }
        for(int i = 0; i < 26; i ++){ 
            int las = (i + tag) % 26;
            tr[u].hash1[las] = t1[i];
            tr[u].hash2[las] = t2[i];
        }
        tr[u].tag = (tr[u].tag + tag) % 26;
    }
}

void pushdown(int u){
    pushdown(lc, tr[u].tag);
    pushdown(rc, tr[u].tag);
    tr[u].tag = 0;
}

void segMove(int u, int l, int r, int v){
    if(l <= tr[u].l && r >= tr[u].r){
        pushdown(u, v);
        return ;
    }
    int mid = tr[u].l + tr[u].r >> 1;
    pushdown(u);
    if(l <= mid) segMove(lc, l, r, v);
    if(r > mid) segMove(rc, l, r, v);
    pushup(u);
}

node askHash(int u, int l, int r){
    if(l <= tr[u].l && r >= tr[u].r){
        return tr[u];
    }
    int mid = tr[u].l + tr[u].r >> 1;
    pushdown(u);
    if(r <= mid) return askHash(lc, l, r);
    else if(l > mid) return askHash(rc, l, r);
    else{
        node res, lres = askHash(lc, l, r), rres = askHash(rc, l, r);
        pushup(res, lres, rres);
        return res;
    }
}

void solve(){
    int n, m;
    cin >> n >> m >> s;
    s = ' ' + s;
    build(1, 1, n);  

    while(m --){
        int op, l, r, v;
        cin >> op >> l >> r;
        if(op == 1){
            node res = askHash(1, l, r);
            int hash1 = 0, hash2 = 0;
            for(int i = 0; i < 26; i ++){
                hash1 = (hash1 + i * res.hash1[i] % mod) % mod;
                hash2 = (hash2 + i * res.hash2[i] % mod) % mod;
            } 
            cout << (hash1 == hash2 ? "YES" : "NO") << '\n';
        }
        else{
            cin >> v;
            segMove(1, l, r, v);
        }
    }
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0); 

    p[0] = 1;
    for(int i = 1; i < N; i ++){
        p[i] = p[i - 1] * P % mod;
    }

    int T = 1;
    while (T --){
        solve();
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值