[LOJ] 分块九题 4

https://loj.ac/problem/6280

区间修改,区间求和。

本来线段树的活。

//Stay foolish,stay hungry,stay young,stay simple
#include<iostream>
#include<cstdio>
#include<cctype>
#include<cmath>

using namespace std;

typedef long long ll;

const int MAXN=500005;

ll sum[MAXN],r[MAXN],l[MAXN],inc[MAXN];
ll a[MAXN],bl[MAXN],block;
ll n,m,num;

inline ll read_d(){
    ll ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c)) f=c=='-'?-1:1;
    while(isdigit(c)){
        ret*=10;ret+=c-'0';c=getchar();
    }
    return ret*f;
}

inline void write(ll x)
{
    if(x<0) x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

inline void build(){
    block=sqrt(n);
    num=n/block;
    if(n%block) num++;
    for(int i=1;i<=num;i++){
        l[i]=(i-1)*block+1;
        r[i]=i*block;
    }
    for(int i=1;i<=n;i++)
        bl[i]=(i-1)/block+1;
    r[num]=n;
    for(int i=1;i<=num;i++)
        for(int j=l[i];j<=r[i];j++)
            sum[i]+=a[j];
}


inline void updata(ll x,ll y,ll w){
    if(bl[x]==bl[y]){
        for(int i=x;i<=y;i++) a[i]+=w;
        sum[bl[x]]+=w*(y-x+1);
        return ;
    }
    for(int i=x;i<=r[bl[x]];i++)
        a[i]+=w,sum[bl[i]]+=w;
    for(int i=bl[x]+1;i<=bl[y]-1;i++)
        inc[i]+=w;
    for(int i=l[bl[y]];i<=y;i++)
        a[i]+=w,sum[bl[i]]+=w;
}

inline ll query(int x,int y){
    ll ret=0;
    if(bl[x]==bl[y]){
        for(int i=x;i<=y;i++) ret+=a[i]+inc[bl[i]];
        return ret;
    }
    for(int i=x;i<=r[bl[x]];i++) ret+=a[i]+inc[bl[i]];
    for(int i=bl[x]+1;i<=bl[y]-1;i++)
        ret+=sum[i]+inc[i]*(r[i]-l[i]+1);
    for(int i=l[bl[y]];i<=y;i++) ret+=a[i]+inc[bl[i]];
    return ret;
}

int main(){
    n=read_d();
    m=n;
    for(int i=1;i<=n;i++)
        a[i]=read_d(); 
    build();
    for(int i=1;i<=m;i++){
        ll q,x,y,z;
        q=read_d();
        x=read_d();
        y=read_d();
        z=read_d(); 
        if(q==0) updata(x,y,z);
        else write(query(x,y)%(z+1)),putchar('\n');//讲道理是得query里每步模的
    }
    return 0;
}
posted @ 2018-04-12 02:05  GhostCai  阅读(98)  评论(0编辑  收藏  举报