洛谷 P5358 [SDOI2019]快速查询
学习线段树的区间懒标记想法,我们把整个区间当作一个区间。
懒标记有\(add,mul,cov\)
\(add\):区间里每个数加上多少。
\(mul\):区间里每个数乘上多少。
\(cov\):最近一次区间赋值的值是多少。
利用上面三个标记,我们就解决了所有区间修改。
但是单点修改呢?
题目中操作种数只有\(10^5\)种,因此所有单点可以单独提取出来离散化一下。
我们考虑单点赋值,赋值后这个点就符合我们上面的懒标记了,所以我们要把这个值改造一下。
最后单点值\(V_i = (a_i + cov) * mul + add\)
然后就可以了。
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e7 + 19;
int n,Q,t;
struct Que{
int opt;
int id; long long val,inv;
}q[100050];
int lsh[100050],ccnt;
long long totsum, totadd, totmul, totinv;
long long cov;
long long temp[100050];
bitset<100050> use;
int U[100050],cnt;
//(temp_i + cov) * totmul + totadd = val_i
long long ksm(long long x,long long y){
long long z = 1;
while(y){
if(y & 1) z = z * x % mod;
y >>= 1;
x = x * x % mod;
}
return z;
}
long long Ans;
void work(int idx){
if(q[idx].opt == 1){
long long tmp = temp[q[idx].id];
tmp += cov; tmp %= mod;
tmp *= totmul; tmp %= mod;
tmp += totadd; tmp %= mod;
tmp = (tmp % mod + mod) % mod;
totsum += q[idx].val - tmp; totsum = (totsum % mod + mod) % mod;
tmp = q[idx].val;
tmp -= totadd; tmp += mod; tmp %= mod;
tmp *= totinv; tmp %= mod;
tmp -= cov; tmp += mod; tmp %= mod;
temp[q[idx].id] = tmp;
if(!use[q[idx].id]) { use[q[idx].id] = 1; U[++ cnt] = q[idx].id; }
}
if(q[idx].opt == 2){
totadd += q[idx].val; totadd %= mod;
totsum += 1ll * n * q[idx].val % mod; totsum %= mod;
}
if(q[idx].opt == 3){
totmul = totmul * q[idx].val % mod; totinv = totinv * q[idx].inv % mod;
totadd = totadd * q[idx].val % mod;
totsum = totsum * q[idx].val % mod;
}
if(q[idx].opt == 4){
totmul = 1; totadd = 0; totinv = 1;
cov = q[idx].val; while(cnt) { temp[U[cnt]] = 0; -- cnt; } use.reset();
totsum = 1ll * n * q[idx].val % mod;
}
if(q[idx].opt == 5){
long long tmp = temp[q[idx].id];
tmp += cov; tmp %= mod;
tmp *= totmul; tmp %= mod;
tmp += totadd; tmp %= mod;
tmp = (tmp % mod + mod) % mod;
Ans += tmp; Ans %= mod;
//printf("%lld\n",tmp);
}
if(q[idx].opt == 6){
totsum = (totsum % mod + mod) % mod;
Ans += totsum; Ans %= mod;
//printf("%lld\n",totsum);
}
}
int main(){
scanf("%d%d",&n,&Q); n %= mod;
for(int i = 1; i <= Q; ++ i){
scanf("%d",&q[i].opt);
if(q[i].opt == 1) scanf("%d%lld",&q[i].id,&q[i].val);
else if(q[i].opt <= 4) scanf("%lld",&q[i].val);
else if(q[i].opt == 5) scanf("%d",&q[i].id);
q[i].val = (q[i].val % mod + mod) % mod;
if(q[i].opt == 3) q[i].inv = ksm(q[i].val, mod - 2);
}
for(int i = 1; i <= Q; ++ i){
if(q[i].opt == 1 || q[i].opt == 5) lsh[++ ccnt] = q[i].id;
}
sort(lsh + 1, lsh + ccnt + 1); ccnt = unique(lsh + 1, lsh + ccnt + 1) - lsh - 1;
for(int i = 1; i <= Q; ++ i){
if(q[i].opt == 1 || q[i].opt == 5) q[i].id = lower_bound(lsh + 1, lsh + ccnt + 1, q[i].id) - lsh;
}
totsum = 0; totmul = 1; totinv = 1; totadd = 0; cov = 0; memset(temp,0,sizeof(temp));
Ans = 0; use.reset(); cnt = 0;
scanf("%d",&t);
for(int i = 0; i < t; ++ i){
int a,b; scanf("%d%d",&a,&b);
long long op = a;
for(int j = 1; j <= Q; ++ j){
op += b; op %= Q;
work(op + 1);
}
}
printf("%lld\n",Ans);
return 0;
}