CodeChef Chef and Churu [分块]

题意:

单点修改$a$

询问$a$的区间和$f$的区间和


原来普通计算机是这道题改编的吧...

对$f$分块,预处理$c[i][j]$为块i中$a_j$出现几次,$O(NH(N))$,只要每个块差分加上然后扫一遍就行了不用树状数组之类的

修改,整块直接改,还要单点修改$a$

查询,整块直接查,两边暴力查询$a$的区间和

对$a$的操作可以用树状数组,也可以再分块维护前缀和实现$O(N)-O(1)$

这样不用带一个log总复杂度$O(NH(N))$

实测快了0.4s

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=1e5+5,M=350;
typedef unsigned long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,Q,op,x,y;
ll a[N],s[N];
int pos[N],m,block;
struct _Block{int l,r;} b[M], f[N];
inline void iniBlock(){
    block=sqrt(n); m=(n-1)/block+1;
    for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
    for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1,b[i].r=i*block;
    b[m].r=n;
}
struct BlockA{
    ll add[M];
    void Add(int x,ll v){
        for(int i=x;i<=b[pos[x]].r;i++) s[i]+=v;
        for(int i=pos[x]+1;i<=m;i++) add[i]+=v;
    }
    ll fun(_Block &x){
        return s[x.r]+add[ pos[x.r] ] - (s[x.l-1]+add[ pos[x.l-1] ]);
    }
}A;
struct Block{
    int c[M][N],s[N];
    ll sum[N];
    void ini(){
        for(int i=1;i<=m;i++){
            for(int j=b[i].l ; j<=b[i].r ; j++)
                s[ f[j].l ]++,s[ f[j].r+1 ]--;
            int *cc=c[i];
            for(int j=1;j<=n;j++) 
                cc[j]=cc[j-1]+s[j],sum[i]+=cc[j]*a[j],s[j]=0;
        }
    }
    void cha(int x,ll v){
        ll t=v-a[x]; A.Add(x,t);
        for(int i=1;i<=m;i++) sum[i]+=c[i][x]*t;
        a[x]=v;
    }
    ll que(int l,int r){
        ll re=0;
        if(pos[l]==pos[r])
            for(int i=l;i<=r;i++) re+=A.fun(f[i]);
        else{
            for(int i=pos[l]+1;i<=pos[r]-1;i++) re+=sum[i];
            for(int i=l;i<=b[pos[l]].r;i++) re+=A.fun(f[i]);
            for(int i=b[pos[r]].l;i<=r;i++) re+=A.fun(f[i]);
        }
        return re;
    }
}B;
int main(){
    freopen("in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i];
    for(int i=1;i<=n;i++) f[i].l=read(),f[i].r=read();
    iniBlock();B.ini();
    Q=read();
    while(Q--){
        op=read();x=read();y=read();
        if(op==1) B.cha(x,y);
        else printf("%llu
",B.que(x,y));
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pii pair<int,int>
#define MP make_pair
#define fir first
#define sec second
const int N=1e5+5,M=350;
typedef unsigned long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,Q,op,x,y;
ll a[N];
pii f[N];
struct BIT{
    ll c[N];
    inline void add(int p,ll v){for(;p<=n;p+=(p&-p)) c[p]+=v;}
    inline ll sum(int p){ll re=0;for(;p;p-=(p&-p)) re+=c[p];return re;}
}C;
inline ll fun(int x){return C.sum(f[x].sec)-C.sum(f[x].fir-1);}
struct _Block{int l,r;ll sum;};
struct Block{
    int block,m,pos[N],c[M][N],s[N];
    _Block b[M];
    void ini(){
        block=sqrt(n); m=(n-1)/block+1;
        for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;

        for(int i=1;i<=m;i++){
            b[i].l=(i-1)*block+1; b[i].r= i==m ? n : i*block;
            for(int j=b[i].l ; j<=b[i].r ; j++)
                s[ f[j].fir ]++,s[ f[j].sec+1 ]--;
            int *cc=c[i];
            for(int j=1;j<=n;j++) cc[j]=cc[j-1]+s[j],b[i].sum+=cc[j]*a[j],s[j]=0;
        }
    }
    void cha(int x,ll v){
        v-=a[x];
        for(int i=1;i<=m;i++) b[i].sum+=c[i][x]*v;
        C.add(x,v); a[x]+=v;
    }
    ll que(int l,int r){
        ll re=0;
        if(pos[l]==pos[r])
            for(int i=l;i<=r;i++) re+=fun(i);
        else{
            for(int i=pos[l]+1;i<=pos[r]-1;i++) re+=b[i].sum;
            for(int i=l;i<=b[pos[l]].r;i++) re+=fun(i);
            for(int i=b[pos[r]].l;i<=r;i++) re+=fun(i);
        }
        return re;
    }
}B;
int main(){
    freopen("in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),C.add(i,a[i]);
    for(int i=1;i<=n;i++) f[i].fir=read(),f[i].sec=read();
    B.ini();
    Q=read();
    while(Q--){
        op=read();x=read();y=read();
        if(op==1) B.cha(x,y);
        else printf("%llu
",B.que(x,y));
    }
}
BIT
原文地址:https://www.cnblogs.com/candy99/p/6553299.html