牛客小白月赛36 J.科学幻想 树状数组+哈希+二分
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客小白月赛36 J.科学幻想 树状数组+哈希+二分相关的知识,希望对你有一定的参考价值。
原题链接:https://ac.nowcoder.com/acm/contest/11213/J
题意
给你一个字符串,你有两种操作
- 改变单个字符
- 询问 [ 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]=l∑rf[i]∗s[i](f[i]=f[i−1]∗base,预处理即可)
如果是修改y位置的s[i],那么我们直接单点修改时加上
f
[
x
]
∗
(
c
−
s
[
i
]
)
f[x]*(c-s[i])
f[x]∗(c−s[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.科学幻想 树状数组+哈希+二分的主要内容,如果未能解决你的问题,请参考以下文章