[2020 CCPC 威海 G] Caesar Cipher

https://codeforces.ml/gym/102798

题意:
给你一段序列,有两种操作。

  • \(1\) \(l\) \(r\),对\([l, r]\)区间内所有数\(+1\)\(mod\ 65536\)
  • \(2\) \(x\) \(y\) \(l\),询问\([x, x + l]\) 是否与\([y, y + l]\)相等

题解:
考虑线段树。需要\(mod\ 65536\),看似不是很好操作,但其实你要从\(0\)加到\(65536\)的周期是比较长的,不会很频繁地更新很多点,所以我们就可以暴力去\(mod\ 65536\)。对于询问区间是否相等,我们可以用线段树来维护区间哈希值,最后取出来比较哈希值即可。

第一次遇到卡自然溢出的题目。卡哈希最重要的不是\(base\)值,而是模数,我们手动取模一下就能过了。保险的话也可以用双哈希维护,判断两种哈希值是否都相同。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll mod = 1e9 + 7;
const int M = 65536;
const ll bas = 131;
const int N = 5e5 + 7;

ll gap[N];
int n, q, a[N], ql, qr, len, op;

struct Seg{
    ll t[N << 2], base[N << 2], maxx[N << 2], lazy[N << 2];
    
    void up(int id) {
        base[id] = (base[id << 1] + base[id << 1| 1]) % mod;
        t[id] = (t[id << 1] + t[id << 1 | 1]) % mod;
        maxx[id] = max(maxx[id << 1], maxx[id << 1 | 1]);
    }
    
    void build(int id, int l, int r) {
        t[id] = maxx[id] = base[id] = lazy[id] = 0;
        if (l == r) {
            base[id] = gap[l - 1];
            maxx[id] = a[l];
            t[id] = (ll)a[l] * base[id] % mod;
            return;
        }
        int mid = l + r >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
        up(id);
    }
    
    void down(int id) {
        if (!lazy[id]) return;
        ll tmp = lazy[id];
        lazy[id] = 0;
        lazy[id << 1] += tmp;
        lazy[id << 1 | 1] += tmp;
        maxx[id << 1] += tmp;
        maxx[id << 1 | 1] += tmp;
        t[id << 1] = (t[id << 1] + (base[id << 1] * tmp) % mod) % mod;
        t[id << 1 | 1] = (t[id << 1 | 1] + (base[id << 1 | 1] * tmp) % mod) % mod;
    }
    
    void modify(int id, int l, int r, int ql, int qr) {
        if (l >= ql && r <= qr) {
            lazy[id]++;
            maxx[id]++;
            t[id] = (t[id] + base[id]) % mod;
            return;
        }
        down(id);
        int mid = l + r >> 1;
        if (ql <= mid) modify(id << 1, l, mid, ql, qr);
        if (qr > mid) modify(id << 1 | 1, mid + 1, r, ql, qr);
        up(id);
    }
    
    ll query(int id, int l, int r, int ql, int qr) {
        if (l >= ql && r <= qr) return t[id];
        down(id);
        ll res = 0;
        int mid = l + r >> 1;
        if (ql <= mid) res = (res + query(id << 1, l, mid, ql, qr)) % mod;
        if (qr > mid) res = (res + query(id << 1 | 1, mid + 1, r , ql ,qr)) % mod;
        return res;
    }
    
    void work(int id, int l, int r) {
        if (maxx[id] < M) return;
        if (l == r) {
            maxx[id] %= M;
            t[id] = base[id] * maxx[id] % mod;
            return;
        }
        down(id);
        int mid = l + r >> 1;
        if (maxx[id << 1] >= M) work(id << 1, l, mid);
        if (maxx[id << 1 | 1] >= M) work(id << 1 | 1, mid + 1, r);
        up(id);
    }
}seg;

bool ok() {
    seg.work(1, 1, n);
    scanf("%d %d %d", &ql, &qr, &len);
    if (qr < ql) swap(ql, qr);
    ll va = seg.query(1, 1, n, ql, ql + len - 1);
    ll vb = seg.query(1, 1, n, qr, qr + len - 1);
    va = va * gap[qr - ql] % mod;
    return va == vb;
}

void solve() {
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    seg.build(1, 1, n);
    for (int i = 1; i <= q; ++i) {
        scanf("%d", &op);
        if (op == 1) {
            scanf("%d%d", &ql, &qr);
            seg.modify(1, 1, n, ql, qr);
        } else {
            if (ok()) puts("yes");
            else puts("no");
        }
    }
}

int main() {
    gap[0] = 1;
    for (int i = 1; i < N; ++i) {
        gap[i] = gap[i - 1] * bas % mod;
    }
    solve();
    return 0;
}

/*
5 6
1 2 1 2 1
2 1 2 2
2 1 3 3
1 1 1
1 3 5
2 1 2 4
2 1 2 2
*/
posted @ 2021-04-02 00:01  stff577  阅读(157)  评论(0)    收藏  举报