题解 CF1746F Kazaee

link

题意

给定一个长度为 n 的序列 am 次操作:

  • ai 修改为 x
  • x appear in[l,r],计 cntxx[l,r] 中的出现次数,查询 cntx 是否均为 k 的倍数。

数据范围:1n,m3×105,1ai,x109

题解

显然有一个 O(n53logn) 的带修莫队做法,当然过不了。

因为有神秘人告诉我,这题和 CSP 2022 的 C 类似,想到赋随机值哈希。

考虑把查询转化为区间和,发现区间和是 k 的倍数答案为 YES 的必要条件,给每个 ai 映射到随机值 bi 上,bit 维护 bi 前缀和。

这种算法在 k 很小时,正确性不高,因为 bi 是随机的,所以区间和也是随机的,当答案为 NO 且区间和为 k 的倍数的概率是 1k,可以考虑多随几组,k=1 时答案肯定为 YESk2 时,随 T 组错误的概率 12T,对于所有询问错误率 m2T,当 T=40,这个错误率已经极小了,可以接受。

时间复杂度 O(Tnlogn),其中 T=40

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5 + 10;
mt19937_64 R;
int Rand(int l, int r) {
    uniform_int_distribution<int> distribution(l, r);
    return distribution(R);
}
int n, m, a[N], lsh[N << 1], cnt;
int rnd[N << 1], b[N];
bool ans[N];
struct query {
    int opt, x, y, k;
} q[N];
namespace bit {
    ll t[N];
    void add(int x, int k) {
        for(int i = x; i <= n; i += i & -i)
            t[i] += k;
    }
    ll qry(int x) {
        ll res = 0;
        for(int i = x; i; i -= i & -i)
            res += t[i];
        return res;
    }
    ll qry(int l, int r) {
        return qry(r) - qry(l - 1);
    }
} using namespace bit;
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]), lsh[++cnt] = a[i];
    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d", &q[i].opt, &q[i].x, &q[i].y);
        if(q[i].opt == 1) lsh[++cnt] = q[i].y;
        else scanf("%d", &q[i].k);
    }
    sort(lsh + 1, lsh + 1 + cnt);
    cnt = unique(lsh + 1, lsh + 1 + cnt) - lsh - 1;
    for(int i = 1; i <= n; i++)
        a[i] = lower_bound(lsh + 1, lsh + 1 + cnt, a[i]) - lsh;
    for(int i = 1; i <= m; i++)
        if(q[i].opt == 1) q[i].y = lower_bound(lsh + 1, lsh + 1 + cnt, q[i].y) - lsh;
    memset(ans, 1, sizeof(ans));
    for(int T = 1; T <= 40; T++) {
        memset(t, 0, sizeof(t));
        for(int i = 1; i <= cnt; i++)
            rnd[i] = Rand(1, 1e9);
        for(int i = 1; i <= n; i++)
            b[i] = a[i];
        for(int i = 1; i <= n; i++)
            add(i, rnd[a[i]]);
        for(int i = 1; i <= m; i++) {
            if(q[i].opt == 1) {
                add(q[i].x, -rnd[b[q[i].x]]);
                b[q[i].x] = q[i].y;
                add(q[i].x, rnd[b[q[i].x]]);
            }
            else ans[i] &= (qry(q[i].x, q[i].y) % q[i].k == 0);
        }
    }
    for(int i = 1; i <= m; i++)
        if(q[i].opt == 2) puts(ans[i] ? "YES" : "NO");
    return 0;
}
posted @   Terac  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示