P6688 可重集 题解
P6688 可重集 题解
比较两个区间是否相同,可以看作两个可重集的比较,而且还要求给区间每个数加上整数 \(k\) 如果能变成另外一个集合,也算作相同。
考虑设计一个巧妙哈希函数,使得可以方便地计算出区间加上 \(k\) 之后的哈希值。
这里我采用了指数作为哈希函数:
\[h_i = base^{a_i}
\]
\(base\) 是一个待定的底数,我取了 \(3\) 作为底数。
对于一个区间 \([l, r]\),它的哈希值即为:
\[h_{[l, r]} = \sum_{i = l}^rbase^{a_i}
\]
这个哈希有一个很好的性质,区间加上 \(k\) 哈希值会变成原来的哈希值乘上 \(base^{k}\):
\[h'_{[l, r]} = \sum_{i = l}^rbase^{a_i + k} = \sum_{i = l}^r(base^{a_i}base^k) = base^k\sum_{i = l}^rbase^{a_i} = base^kh_{[l, r]}
\]
为了比较两个区间是否相同,我们可以给较小的区间集体加上两个区间最小值的差值,再比较两个区间哈希值是否相同即可。
修改操作用线段树维护就好了。
时间复杂度:\(O(m\log n)\)
// Problem: P6688 可重集
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-07-31 21:13:31
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <set>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10, mod = 1e9 + 7, base = 3;
int n, q;
int a[N];
int qmi(int a, int b)
{
int res = 1;
while(b)
{
if(b & 1) res = 1ll * res * a % mod;
b >>= 1, a = 1ll * a * a % mod;
}
return res;
}
int l[N << 2], r[N << 2], dat[N << 2], sum[N << 2];
void up(int u) {dat[u] = min(dat[u << 1], dat[u << 1 | 1]), sum[u] = 1ll * (sum[u << 1] + sum[u << 1 | 1]) % mod;}
void build(int u, int tl, int tr)
{
l[u] = tl, r[u] = tr, dat[u] = 1e9 + 10, sum[u] = 0;
if(tl == tr) sum[u] = qmi(base, a[tl]), dat[u] = a[tl];
else build(u << 1, tl, tl + tr >> 1), build(u << 1 | 1, (tl + tr >> 1) + 1, tr), up(u);
}
void update(int u, int x, int v)
{
int mid = l[u] + r[u] >> 1;
if(x == l[u] && r[u] == l[u])
return (void)(dat[u] = v, sum[u] = qmi(base, v) % mod);
if(x <= mid) update(u << 1, x, v);
else update(u << 1 | 1, x, v);
up(u);
}
PII query(int u, int ql, int qr)
{
int mid = l[u] + r[u] >> 1;
if(ql <= l[u] && qr >= r[u])
return {dat[u], sum[u]};
PII tmp = {1e9 + 10, 0};
if(ql <= mid)
{
auto t = query(u << 1, ql, qr);
tmp.x = min(tmp.x, t.x), tmp.y = 1ll * (tmp.y + t.y) % mod;
}
if(qr > mid)
{
auto t = query(u << 1 | 1, ql, qr);
tmp.x = min(tmp.x, t.x), tmp.y = 1ll * (tmp.y + t.y) % mod;
}
return tmp;
}
signed main()
{
n = read(), q = read();
for(int i = 1; i <= n; i ++)
a[i] = read();
build(1, 1, n);
while(q --)
{
int op, a, b, c, d;
op = read(), a = read(), b = read();
if(!op)
update(1, a, b);
else
{
c = read(), d = read();
auto q1 = query(1, a, b);
auto q2 = query(1, c, d);
if(q1.x < q2.x)
{
int t = 1ll * qmi(base, q2.x - q1.x) * q1.y % mod;
cout << (t == q2.y ? "YES" : "NO") << '\n';
}
else
{
int t = 1ll * qmi(base, q1.x - q2.x) * q2.y % mod;
cout << (t == q1.y ? "YES" : "NO") << '\n';
}
}
}
return 0;
}