[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;
}
[SDOI2019] 快速查询

 

posted @ 2020-06-09 21:06  Fugtemypt  阅读(247)  评论(0编辑  收藏  举报