牛客小白月赛36 J.科学幻想 树状数组+哈希+二分

Posted kaka0010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客小白月赛36 J.科学幻想 树状数组+哈希+二分相关的知识,希望对你有一定的参考价值。

原题链接:https://ac.nowcoder.com/acm/contest/11213/J

题意

给你一个字符串,你有两种操作

  1. 改变单个字符
  2. 询问 [ l 1 , r 1 ] 和 [ l 2 , r 2 ] [l1,r1]和[l2,r2] [l1,r1][l2,r2]是否勉强相等(相同位置最多只有一个位置不同)

分析

很久没在小白月赛写到数据结构题了,其实思路不难想,但比赛被卡线段树了,有点难受
看到询问字符串是否相等,基本上可以确定是哈希,然后是待修改的哈希,直接在树状数组上维护一下就好了。我们看
H a s h [ l , r ] = ∑ l r f [ i ] ∗ s [ i ] ( f [ i ] = f [ i − 1 ] ∗ b a s e , 预 处 理 即 可 ) Hash[l,r]=\\sum_{l}^{r}f[i]*s[i](f[i]=f[i-1]*base,预处理即可) Hash[l,r]=lrf[i]s[i](f[i]=f[i1]base)
如果是修改y位置的s[i],那么我们直接单点修改时加上 f [ x ] ∗ ( c − s [ i ] ) f[x]*(c-s[i]) f[x](cs[i])就可以了。

然后就是本题的核心思想,二分。

递归查询[l,r]区间,如果[l,mid]和[mid+1, r]区间都不相同,说明至少有两个地方不对,直接返回false。如果只有左边区间不相同,我们递归左区间,不然递归右区间。

最后,树状数组真香~

Code

#include <bits/stdc++.h>
using namespace std;
#define re register
#define fi first
#define se second
#define please_AC return 0
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int INF = 1e9;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
ll f[N], c[N];
char s[N];
int lowbit(int x) {return x &-x;}
void add(int x, ll val) {
    for (int i = x; i < N; i += lowbit(i)) c[i] += val, c[i] %= MOD;
}
ll qry(int x) {
    ll ans = 0;
    for (int i = x; i > 0; i -= lowbit(i)) ans += c[i], ans %= MOD;
    return ans;
}
ll query(int l, int r) {
    return (qry(r) - qry(l-1) + MOD) % MOD;
}
void init() {
    f[0] = 1;
    for (int i = 1; i < N; i++) f[i] = f[i-1] * 10007 % MOD;
}
int comp(int l1, int r1, int l2, int r2) {
    return (query(l1, r1) * f[l2-l1] % MOD) == query(l2, r2);
}
bool dfs(int l1, int r1, int l2, int r2) {
    if (l1 == r1) return true;
    int mid1 = (l1 + r1) >> 1;
    int mid2 = (l2 + r2) >> 1;

    bool f1 = comp(l1, mid1, l2, mid2);
    bool f2 = comp(mid1 + 1, r1, mid2 + 1, r2);
    if (!f1 && !f2) return false;
    if (!f1) return dfs(l1, mid1, l2, mid2);
    else return dfs(mid1 + 1, r1, mid2 + 1, r2);
}
void solve() {
    init();
    int n, m; cin >> n >> m;
    cin >> (s + 1);
    for (int i = 1; i <= n; i++) add(i, f[i] * s[i] % MOD);
    while (m--) {
        int opt, x, l1, l2, r1, r2;
        char c;
        cin >> opt;
        if (opt == 1) {
            cin >> x >> c;
            int p = (c - s[x] + MOD) % MOD;
            add(x, p * f[x]);
            s[x] = c;
        } else {
            cin >> l1 >> r1 >> l2 >> r2;
            if (l1 > l2) swap(l1, l2), swap(r1, r2);
            if (r2 - l2 != r1 - l1) {
                puts("NO");
                continue;
            }
            if (comp(l1, r1, l2, r2)) {
                puts("YES");
                continue;
            }
            if (dfs(l1, r1, l2, r2)) puts("YES");
            else puts("NO");
        }
    }
}

signed main() {
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#endif

    solve();
    return 0;
}

以上是关于牛客小白月赛36 J.科学幻想 树状数组+哈希+二分的主要内容,如果未能解决你的问题,请参考以下文章

牛客小白月赛34 ACEF(待补)

牛客网小白月赛34题解

牛客网小白月赛34题解

牛客网小白月赛34题解

牛客小白月初赛38-J科学幻想(线段树维护字符串哈希+二分)

牛客小白月初赛38-J科学幻想(线段树维护字符串哈希+二分)