[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;
}
看不见我看不见我看不见我