[SDOI2019] 快速查询
题意:
给定一个长度为n的整数数列。初始的时候所有元素都为零。
现在按照时间顺序提供了$t\times q$次关于这个数列的修改或询问,每一次修改或询问一定为以下六种情况之一:
- 1 i val:将$a_{i}$赋值为给定整数val;
- 2 val:将所有元素同时加上val;
- 3 val:将所有元素同时乘上val;
- 4 val:将所有元素同时赋值为val;
- 5 i:询问第$a_{i}$个元素现在的值是多少;
- 6:询问现在所有元素的和。
现在请你求出所有询问答案之和对$10^{7}+19$取模的结果。
$n\leq 10^{9},q\leq 10^{5},t\leq 100,-10^{9}\leq val\leq 10^{9},本质不同的询问有q个$。
题解:
需要做到$O(1)$处理询问,所以肯定跟数据结构没关系了。
注意到被修改过的元素最多有$10^{5}$个,那么我们可以单独维护这些元素,设该序列为V。
然后维护一个oth表示没被修改过的元素当前的值,再维护一个当前序列之和sum。
考虑怎么维护2,3操作,类似于线段树进行加乘,我们维护mul,add标记,满足$a_{i}=V_{i}\times mul+add$。
注意一个极其严重的问题:如果有3 0操作那么mul标记会等于0,显然mul不能为0,所以需要把所有3 0操作改成4 0操作。
考虑怎么维护4操作,直接平推掉序列,令$sum=val\times n,add=0,mul=1$,暂时不管V。
考虑怎么维护1操作,先将原来的$V_{i}$从sum里减掉,新的$V'_{i}$需要满足$V'_{i}\times mul+add=val$,移项可得$V'_{i}=\frac{val-add}{mul}$。
注意到我们没把4操作的影响计入V,于是需要记录最后一次4操作和最后一次操作$V_{i}$的时间戳并比较大小:如果后者大则$V_{i}=V_{i}$,否则$V_{i}=oth$。
复杂度$O(tq)$,其实并不难,主要是样例实在难调(
套路:
- 使用$lazytag$时:整体乘法标记是不能为0的。
- 使用$lazytag$时:将“当前值”和“实际值”的关系整理清晰。
- 线性筛逆元公式:$inv(x)=inv(p\% x)\times(p/x)$。(或者用阶乘求)
代码:
#include<bits/stdc++.h> #define maxn 100005 #define maxm 500005 #define inf 0x7fffffff #define mod 10000019 #define ll long long #define rint register int #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; ll las[maxn],V[maxn],inv[mod+5]; map<ll,ll> mp; struct Question{ll type,p,val;}Q[maxn]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline int mo(int x){return x>=mod?x-mod:x;} int main(){ ll n=read(),q=read(); for(rint i=1;i<=q;i++){ Q[i].type=read(); if(Q[i].type==1) Q[i].p=read(),Q[i].val=(read()%mod+mod)%mod,mp[Q[i].p]=i; else if(Q[i].type==2) Q[i].val=(read()%mod+mod)%mod; else if(Q[i].type==3){ Q[i].val=(read()%mod+mod)%mod; if(Q[i].val==0) Q[i].type=4; } else if(Q[i].type==4) Q[i].val=(read()%mod+mod)%mod; else if(Q[i].type==5) Q[i].p=read(); } ll T=read(),sum=0,mul=1,add=0,oth=0,ans=0; inv[1]=1; for(rint i=2;i<mod;i++) inv[i]=mod-inv[mod%i]*(mod/i)%mod; for(rint t=1;t<=T;t++){ ll a=read(),b=read(); for(rint j=1;j<=q;j++){ ll i=(a+j*b)%q+1; if(Q[i].type==1){ ll x=mp[Q[i].p]; if(las[0]>las[x]) sum=mo(sum-oth+mod); else sum=mo(sum-mo(V[x]*mul%mod+add)+mod); V[x]=mo(Q[i].val-add+mod)*inv[mul]%mod; sum=mo(sum+mo(V[x]*mul%mod+add)),las[x]=q*(t-1)+j; } if(Q[i].type==2) sum=mo(sum+n*Q[i].val%mod),add=mo(add+Q[i].val),oth=mo(oth+Q[i].val); if(Q[i].type==3) sum=sum*Q[i].val%mod,mul=mul*Q[i].val%mod,add=add*Q[i].val%mod,oth=oth*Q[i].val%mod; if(Q[i].type==4) sum=Q[i].val*n%mod,mul=1,add=0,oth=Q[i].val,las[0]=q*(t-1)+j; if(Q[i].type==5){ if(!mp[Q[i].p]) ans=mo(ans+oth); else{ ll x=mp[Q[i].p]; if(las[0]>las[x]) ans=mo(ans+oth); else ans=mo(ans+mo(V[x]*mul%mod+add)); } } if(Q[i].type==6) ans=mo(ans+sum); } } printf("%lld\n",ans); return 0; }