数列分块1(学习)

题目传送门

适用范围:区间修改,单点查询。

思想:分块操作,将个数作为一组(一块)。

每次操作会涉及最多个块和包括左右区间不完整最多个 元素。

即每次操作的复杂度大约在:

根据均值不等式最合适。

总复杂度:

树状数组做法待补

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
int a[N],bk,n,tag[N],bl[N];
void add(int l,int r,int c){
    for(int i=l;i<=min(bl[l]*bk,r);i++) //左端不完整块暴力修改 
        a[i]+=c;
    if(bl[l]!=bl[r]) //防止加重. 
        for(int i=(bl[r]-1)*bk+1;i<=r;i++) //右端不完整块暴力修改 
            a[i]+=c;
        for(int i=bl[l]+1;i<=bl[r]-1;i++) //每块修改. 
            tag[i]+=c;
} 
int main(){
    scanf("%d",&n);bk=sqrt(n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) bl[i]=(i-1)/bk+1;
    for(int i=1,op,l,r,c;i<=n;i++){
        scanf("%d%d%d%d",&op,&l,&r,&c);
        if(!op) add(l,r,c);
        else printf("%d\n",a[r]+tag[bl[r]]);
    }
    return 0;
} 

线段树做法:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e6+5;
struct node{ //结构体线段树板子. 
    int l,r,s,lz;//[l,r],sum,lzay tag 
}a[N];
void re(int x){ //refresh 更新和sum 
    a[x].s=a[x<<1].s+a[x<<1|1].s; 
}
void pushdown(int x){ //下放标记. 
    if(a[x].lz){
        a[x<<1].lz+=a[x].lz,a[x<<1|1].lz+=a[x].lz;
        a[x<<1].s+=(a[x<<1].r-a[x<<1].l+1)*a[x].lz;
        a[x<<1|1].s+=(a[x<<1|1].r-a[x<<1|1].l+1)*a[x].lz;
        a[x].lz=0;
    }
}
void build(int x,int l,int r){
    a[x].l=l,a[x].r=r,a[x].lz=0;
    if(l==r){
        scanf("%d",&a[x].s);
        return;
    } 
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
} 
void update(int x,int l,int r,int val){  ///update和query都需要pushdown 
     if(l<=a[x].l&&a[x].r<=r){ //更新. 
          a[x].s+=(a[x].r-a[x].l+1)*val;
         a[x].lz+=val;
         return; 
     }
     pushdown(x);
     int mid=(a[x].l+a[x].r)>>1;
     if(l<=mid) update(x<<1,l,r,val);
     if(r>mid) update(x<<1|1,l,r,val);
     re(x);
}
int  query(int x,int l,int r){
     if(l<=a[x].l&&a[x].r<=r) return a[x].s;
     else if(a[x].r<l||a[x].l>r) return 0;
     pushdown(x);
     int mid=(a[x].l+a[x].r)>>1;
     return query(x<<1,l,r)+query(x<<1|1,l,r);
}
int main(){
    int n;
    scanf("%d",&n);
    build(1,1,n);
    for(int i=1,op,l,r,val;i<=n;i++){
         scanf("%d%d%d%d",&op,&l,&r,&val);
         if(!op) update(1,l,r,val);
         else printf("%d\n",query(1,r,r));
    }
    return 0;
}