數列分塊1(學習)

數列分塊1(學習)

題目傳送門

適用範圍:區間修改,單點查詢。

思想:分塊操作,將bk(block)bk(block)個數作爲一組(一塊)。

每次操作會涉及最多nbl\dfrac{n}{bl}個塊和包括左右區間不完整最多2bl2bl個 元素。

即每次操作的複雜度大約在:O(nbl+bl)O(\dfrac{n}{bl}+bl)

根據均值不等式bl=n\rightarrow bl=\sqrt{n}最合適。

總複雜度:O(nn)O(n\sqrt{n})

樹狀數組做法待補\dots\dots

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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章