P5358 [SDOI2019]快速查询 思维题

题意:

戳这里

分析:

  • 暴力

随便来个数据结构直接模拟,但是操作量达到了 (1e7) 级别,也就是说单个操作必须做到 (O(1))

  • 正解

观察发现只有全局操作和单点操作,所以用到了一个小 (trick) 就是维护一个全局标记,然后对于单点进行修改,这样可以做到 (O(1)) 进行全局修改,然后对于单点修改操作转化一下也可以做到 (O(1))

具体来说就是:

维护一个全局乘标记 (mul) 全局加标记 (add) 全局赋值标记 (tag) 全局和 (sum) 时间戳 (lst) 每一个点最近第一次单点赋值 (tim[])

这样每一个位置的值等价于 (v[x]*mul+add) ,然后我们开始分操作考虑怎么维护

  1. 单点赋值 (val)

我们逆向推出 (v[pos]) 应该变成什么 (v[pos]*mul+add=val o v[pos]=(val-add) imes inv(mul)) 然后直接修改 (v[pos]) 的值就好了

  1. 全局加 (val)

(add=add+val sum=sum+val*n)

  1. 全局乘 (val)

(add=add*val mul=mul*val sum=sum*val) 注意由于 (0) 没有逆元所以乘 (0) 的操作要看成全局赋值 (0)

  1. 全局赋值 (val)

(tag=val mul=1 add=0 sum=val*n) 同时更新一下 (lst)

  1. 单点查询

分情况讨论一下

(a) : 上一次全局修改在这一个点的单点赋值之前,也就是说全局赋值被覆盖了,那么 (ans=v[pos]*mul+add)

(b) : 上一次全局修改在单点修改之后,也就是说此时的值应该为全局赋值标记 (ans=tag*mul+add)

  1. 全局查询

直接上 (sum)

由于这题读入比较诡异,所以我们可以离散化出修改的点的坐标,这样就可以开的下 (v,tim)

tip:

诡异的读入要求 (a,b) 必须开成 (long long) 不然两个 (int) 相乘直接爆炸,不要问我怎么知道的/kk

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
    long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const int maxn = 1e5+5;
    const long long mod = 1e7+19;
    long long n,qt,cnt,t,lst,sum,ans,mul,add,tag;
    long long d[maxn],tim[maxn],inv[mod+5],v[maxn];
    struct query
    {
        long long opt,pos,val;
    }q[maxn];
    
    void init()
    {
        inv[1]=inv[0]=1;
        for(int i=2;i<mod;i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod;
        n=read();qt=read();
        for(int i=1;i<=qt;i++)
        {
            q[i].opt=read();
            if(q[i].opt==1||q[i].opt==5) q[i].pos=read(),d[++cnt]=q[i].pos;
        	if(q[i].opt<=4) q[i].val=read(),q[i].val=(q[i].val%mod+mod)%mod;
        	if(q[i].opt==3&&q[i].val==0) q[i].opt=4;
        }
        sort(d+1,d+cnt+1);
        cnt=unique(d+1,d+cnt+1)-d-1;
        for(int i=1;i<=qt;i++) if(q[i].opt==1||q[i].opt==5) q[i].pos=lower_bound(d+1,d+cnt+1,q[i].pos)-d;
        mul=1;tag=0;add=0;lst=0;
    }

    void work()
    {
        long long a,b,id;
        init();
        t=read();
        for(int i=1;i<=t;i++)
        {
            a=read();b=read();
            for(int j=1;j<=qt;j++)
            {
                id=(a+j*b)%qt+1;
                if(q[id].opt==1)
                {
                    if(tim[q[id].pos]<=lst) sum=(sum-(tag*mul%mod+add)%mod+mod)%mod;
                    else sum=(sum-(v[q[id].pos]*mul%mod+add)%mod+mod)%mod;
                    sum=(sum+q[id].val)%mod;
                    tim[q[id].pos]=(i-1)*qt+j;
                    v[q[id].pos]=(q[id].val-add+mod)%mod*inv[mul]%mod;
                }
                else if(q[id].opt==2)
                {
                    add=(add+q[id].val)%mod;
                    sum=(sum+n*q[id].val%mod)%mod;
                }
                else if(q[id].opt==3)
                {
                    add=add*q[id].val%mod;
                    mul=mul*q[id].val%mod;
                    sum=sum*q[id].val%mod;
                }
                else if(q[id].opt==4)
                {
                    lst=(i-1)*qt+j;
                    tag=q[id].val;
                    mul=1;add=0;
                    sum=n*q[id].val%mod;
                }
                else if(q[id].opt==5)
                {
                    if(tim[q[id].pos]<=lst) ans=(ans+(tag*mul%mod+add)%mod)%mod;
                    else ans=(ans+(v[q[id].pos]*mul%mod+add)%mod)%mod;
                }
                else if(q[id].opt==6)
                {
                    ans=(ans+sum)%mod;
                }
//                printf("#%d: id=%d mul=%d add=%d tag=%d sum=%lld %lld
",(i-1)*qt+j,id,mul,add,tag,sum,ans);
            }
        }
        printf("%lld
",ans%mod);
    }

}

int main()
{
    zzc::work();
    return 0;
}
原文地址:https://www.cnblogs.com/youth518/p/14257470.html