bzoj3188 [ツォツィ2011]要求(分块)

制限時間:10秒   メモリ制限:128メガバイト

説明

あなたは、次の4つの操作をサポートし、順序を維持する必要があります。まず、区間の数は(U、V)カバレッジがCであり、2つの
連続算術配列を付加する間隔の数(U、V)は公差の項目C、Cにつながった; 3、Cの数が中に挿入され、
第私ポジション;第四に、クエリー間隔(U、V)と数。最初のシーケンス番号N、Qは総時間の動作になります
ため。LONGLONGは、範囲内の結果を保証します。 
 

サンプル入力

5
1 2 3 4 5
1 5 0
4 4
4 5 5
2 1 5 1
4 1 5

サンプル出力

4
0
25

ヒント

nは、Q <= 100,000。 

 


 

私は実際にブロックのようなので、私はこのタイトルの後にブロックを使用しました

挿入のサポートに加え、レンジ、変性ブロック、ライン上で遊んでベクトルメンテナンスマーカー配列

ブロックは、(水は非常に無関係なデータを思わ)ホットのような二つに暴力的な分割、大きすぎる場合

列番号、開始のコードブロック番号0から

 

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#define ri register int
using namespace std;
typedef long long ll;
ll read(){
    char c=getchar(); ll x=0; bool f=1;
    while(c<'0'||c>'9') f=f&&(c!='-'),c=getchar();
    while('0'<=c&&c<='9') x=x*10+c-48,c=getchar();
    return f?x:-x;
}
#define N 60005
int n,Q,idm,B,sm[N];
ll s[N],w[N],d[N],k[N];
bool a[N],b[N];
vector <int> h; //从左到右块的编号
vector <ll> g[N];
inline ll G(int x){return g[x].size();}
inline int id(int x){return lower_bound(sm+1,sm+idm+1,x)-sm-1;}//x属于哪个块
void down(int x){
    if(a[x]) s[x]=G(x)*w[x],g[x].assign(G(x),w[x]),a[x]=w[x]=0;
    if(b[x]){
        ll q=d[x],q2=k[x],t=0; b[x]=k[x]=d[x]=s[x]=0;
        for(ri i=0;i<G(x);++i) t+=q,g[x][i]+=t+q2,s[x]+=g[x][i];
    }
}
void cover(int x,int y,ll v){
    ri ix=id(x),iy=id(y),L=h[ix],R=h[iy],l=x-sm[ix]-1,r=y-sm[iy]-1;
    if(L==R){
        down(L);
        for(ri i=l;i<=r;++i) s[L]+=(v-g[L][i]),g[L][i]=v;
        return ;
    }down(L),down(R);
    for(ri i=l;i<G(L);++i) s[L]+=(v-g[L][i]),g[L][i]=v;
    for(ri j=ix+1,i;j<iy;++j) i=h[j],s[i]=v*G(i),b[i]=k[i]=d[i]=0,w[i]=v,a[i]=1;
    for(ri i=0;i<=r;++i) s[R]+=(v-g[R][i]),g[R][i]=v;
}
void add(int x,int y,ll v){
    ri ix=id(x),iy=id(y),L=h[ix],R=h[iy],l=x-sm[ix]-1,r=y-sm[iy]-1; ll q=0;
    if(L==R){
        down(L);
        for(ri i=l;i<=r;++i) q+=v,s[L]+=q,g[L][i]+=q;
        return ;
    }down(L),down(R);
    for(ri i=l;i<G(L);++i) q+=v,s[L]+=q,g[L][i]+=q;
    for(ri j=ix+1,i;j<iy;++j){
        i=h[j];
        if(a[i]){
            s[i]=G(i)*w[i];
            if(b[i]) s[i]+=(d[i]+d[i]*G(i))*G(i)/2+k[i]*G(i);
        }
        s[i]+=(v+v*G(i))*G(i)/2+q*G(i); 
        b[i]=1; d[i]+=v; k[i]+=q; q+=v*G(i);
    }
    for(ri i=0;i<=r;++i) q+=v,s[R]+=q,g[R][i]+=q;
}
void split(int x){
    ri ix=id(x),L=h[ix];
    h.insert(h.begin()+ix+1,idm);
    for(ri i=B;i<G(L);++i)
        g[idm].push_back(g[L][i]),s[idm]+=g[L][i],s[L]-=g[L][i];
    g[L].erase(g[L].begin()+B,g[L].end()); idm++;
}
void ins(int x,ll v){
    ri ix=id(x),L=h[ix],l=x-sm[ix]-1;
    down(L); g[L].insert(g[L].begin()+l,v); s[L]+=v;
    if(G(L)>B*2) split(x);//暴力拆块
    for(ri i=0;i<idm;++i) sm[i+1]=sm[i]+G(h[i]);
}
ll ask(int x,int y){
    ri ix=id(x),iy=id(y),L=h[ix],R=h[iy],l=x-sm[ix]-1,r=y-sm[iy]-1; ll re=0;
    if(L==R){
        down(L);
        for(ri i=l;i<=r;++i) re+=g[L][i];
        return re;
    }down(L),down(R);
    for(ri i=l;i<G(L);++i) re+=g[L][i];
    for(ri j=ix+1;j<iy;++j) re+=s[h[j]];
    for(ri i=r;i>=0;--i) re+=g[R][i];
    return re;
}
int main(){
    n=read(),Q=read(); ll q,x,y; sm[0]=-1; B=sqrt(n);
    for(ri i=0;i<n;++i) q=read(),g[i/B].push_back(q),s[i/B]+=q;
    while(idm*B<=n) sm[idm+1]=sm[idm]+G(idm),h.push_back(idm++);//sm[i]:第$i-1$块的右端点
    while(Q--){
        q=read(),x=read(),y=read();
        if(q==1) cover(x-1,y-1,read());
        if(q==2) add(x-1,y-1,read());
        if(q==3) ins(x-1,y);
        if(q==4) printf("%lld\n",ask(x-1,y-1));
    }return 0;
}

 

 

 

おすすめ

転載: www.cnblogs.com/kafuuchino/p/11518020.html