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;
}
posted @ 2023-08-01 09:51  MoyouSayuki  阅读(149)  评论(0编辑  收藏  举报
:name :name