#根号分治,分块#洛谷 5309 [Ynoi2011] 初始化

题目传送门


分析

如果 \(x\) 比较大那么可以暴力修改,\(x\) 比较小的话可以用数组打标记

查询的时候对于暴力修改的部分可以分块,暴力修改的同时需要给块打标记

如果 \(x\) 比较小的情况,一段区间相当于是中间很多段周期加上前后缀(当然可以直接区间减但是我被卡常了)

我调的块长是160然后询问的时候开了long long最后取模,惊险卡过


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=200011,mod=1000000007;
int n,m,bl,a[N],s[1331],pre[161][161],suf[161][161],pos[N];
int iut(){
    int ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
int query(int x,int y){
    long long ans=0;
    for (int i=1;i<=bl;++i){
        int px=(x-1)/i+1,py=(y-1)/i+1;
        int Px=(x-1)%i+1,Py=(y-1)%i+1;
        if (px==py) ans+=pre[i][Py]-pre[i][Px-1];
            else ans+=((py-px-1ll)*pre[i][i]+suf[i][Px]+pre[i][Py])%mod;
    }
    return (ans%mod+mod)%mod;
}
int main(){
    n=iut(),m=iut(),bl=160;
    for (int i=1;i<=n;++i){
        a[i]=iut();
        if (a[i]==mod) a[i]=0;
        pos[i]=(i-1)/bl+1,Mo(s[pos[i]],a[i]);
    }
    for (int i=1;i<=m;++i)
    if (iut()==1){
        int x=iut(),y=iut(),z=iut();
        if (z==mod) continue;
        if (x>bl) for (int i=y;i<=n;i+=x) Mo(s[pos[i]],z),Mo(a[i],z);
        else{
            for (int i=y;i<=x;++i) Mo(pre[x][i],z);
            for (int i=1;i<=y;++i) Mo(suf[x][i],z);
        }
    }else{
        int l=iut(),r=iut();
        long long ans=query(l,r);
        if (pos[l]==pos[r]){
            for (int j=l;j<=r;++j) ans+=a[j];
        }else{
            for (int j=l;j<=pos[l]*bl;++j) ans+=a[j];
            for (int j=pos[l]+1;j<pos[r];++j) ans+=s[j];
            for (int j=r;j>(pos[r]-1)*bl;--j) ans+=a[j];
        }
        print(ans%mod),putchar(10);
    }
    return 0;
}
posted @ 2024-02-21 19:09  lemondinosaur  阅读(5)  评论(0编辑  收藏  举报