[SDOI2019] 快速查询

[SDOI2019] 快速查询

这题昨天就会了,

但是现在才写出来...

就是因为不会用map...

淦!

这道题其实不难,

首先,

我们发现这个题的操作只有单点和整体,

所以我们维护一个 \(sum\) ,

还有 \(add, mul\) 两个标记.

这样我们每次单点修改的时候,

如果需要修改成 \(val\) ,

那我们就修改成 \((val - add) / mul\) ,

因为我们需要取模,

所以这里就不能除,

只能乘 \(mul\) 的逆元.

因为除了单点修改,

我们还有一个整体赋值的操作,

如果暴力修改就会很慢,

我们就可以维护一个值 \(last\) 和一个数组 \(tim\) ,

\(last\) 表示最后一次整体赋值的时间,

\(tim[i]\) 代表第 \(i\) 个数最后一次单点赋值时间.

这样我们每次访问这一个点,

都只需要比较一下 \(last\)\(tim\) 的值就好了.

然后我们发现 \(n \leq 10 ^ 9\) .

好像...

开不下...

淦!

于是这里我们就有一个小技巧,

虽然 \(n\) 大,

但是 \(q\) 小啊,

因为我们最多对 \(q\)\(a\) 进行操作,

所以我们就给这些个需要修改值编号,

我是用的map实现,

然后这个题就完了,

其余的操作跟线段树差不太多.

code:

#include <cstdio>
#include <iostream>
#include <map>
typedef long long ll;
const int N = 1e5 + 5, mod = 1e7 + 19;
int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)){
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)){
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
int n, q, t, opt[N], num[N], last, tot, tim[N];
ll val[N], a[N], b[N], v[N], inv[mod], sum, ans, add, mul = 1;
std::map <int, int> mp;
void solve(int x, int t){
    if (opt[x] == 1){
        if (tim[num[x]] < last) sum = (sum - (v[0] * mul % mod + add) % mod + mod) % mod;
        else sum = (sum - (v[num[x]] * mul % mod + add) % mod + mod) % mod;
        sum = (sum + val[x]) % mod;
        v[num[x]] = (val[x] - add + mod) * inv[mul] % mod;
        tim[num[x]] = t;
    }
    if (opt[x] == 2){
        sum = (sum + val[x] * n % mod) % mod;
        add = (add + val[x]) % mod;
    }
    if (opt[x] == 3){
        sum = sum * val[x] % mod;
        mul = mul * val[x] % mod;
        add = add * val[x] % mod;
    }
    if (opt[x] == 4){
        sum = n * val[x] % mod;
        v[0] = val[x];
        add = 0;
        mul = 1;
        last = t;
    }
    if (opt[x] == 5){
        if (tim[num[x]] < last) ans = (ans + v[0] * mul + add) % mod;
        else ans = (ans + v[num[x]] * mul + add) % mod;
    }
    if (opt[x] == 6) ans = (ans + sum) % mod;
}
int main(){
    inv[1] = 1;
    for (int i = 2; i < mod; i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    n = read(), q = read();
    for (int i = 1; i <= q; i++){
        opt[i] = read();
        if (opt[i] == 1){
            num[i] = read(), val[i] = (read() % mod + mod) % mod;
            if (!mp[num[i]]) mp[num[i]] = ++tot; //给需要修改的a编号
        }
        if (opt[i] == 2 || opt[i] == 3 || opt[i] == 4) val[i] = (read() % mod + mod) % mod;
        if (opt[i] == 3 && val[i] == 0) opt[i] = 4;
        if (opt[i] == 5) num[i] = read();
    }
    t = read();
    for (int i = 1; i <= t; i++) a[i] = read(), b[i] = read();
    for (int i = 1; i <= q; i++){
        if (opt[i] == 1 || opt[i] == 5){
            num[i] = mp[num[i]];//把a的下标换成编号
        }
    }
    for (int i = 1; i <= t; i++){
        for (int j = 1; j <= q; j++){
            int x = (a[i] + j * b[i] % q) % q + 1;
            solve(x, (i - 1) * q + j);
        }
    }
    printf("%lld", ans);
    return 0;
}
posted @ 2021-08-22 16:32  sshadows  阅读(61)  评论(0编辑  收藏  举报