數列分塊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;
}