数列分块入门 1 LibreOJ - 6277-----------------------分块

给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。

Input
第一行输入一个数字 n。

第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。

接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。

若 opt=0,表示将位于 [l,r] 的之间的数字都加 c。

若 opt=1,表示询问 ar 的值(l 和 c 忽略)。

Output
对于每次询问,输出一行一个数字表示答案。

Example
样例输入

4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0
样例输出
2
5
Hint
对于 100% 的数据,1≤n≤50000,−231≤others、ans≤231−1。
解析:
分块入门 区间更新+单点查询

对于区间的更新:
1.如果更新的区间在同一块中,我们暴力更新即可
2.如果更新的区间在不在同一块中,我们就要暴力修改左侧和右侧不完整的块
对于中间完整的块用懒惰标记记录该块需要+v

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1000;
typedef long long ll;
ll a[N];
int l[N];//第i块的左端点 
int r[N];//第i块的右端点 
ll lazy[N];//对于完整的块 打上lazy 
int pos[N]; //第i个点属于第几块 
int op,u,v,x,n;
void add(int ql,int qr,ll x)
{
	int pl=pos[ql];//要修改的区间左端点属于第几个块 
	int pr=pos[qr];//要修改的区间右端点属于第几个块
	if(pl==pr)//属于同一块暴力修改 
	{
		for(int i=ql;i<=qr;i++) a[i]+=x; 
	 } 
	 else //不同块中 
	 {
	 	for(int i=ql;i<=r[pl];i++)  a[i]+=x; //暴力修改左侧不完整的块
		 
		for(int i=pos[ql]+1;i<=pos[qr]-1;i++) lazy[i]+=x; //计算中间完整的块 
		 
		for(int i=l[pr];i<=qr;i++)  a[i]+=x;//暴力修改右侧不完整的块 
	 }
 } 
ll query(int i)
 {
 	int x=pos[i];//看i是第几块的 
 	if(lazy[x]) return a[i]+lazy[x]; 
 	else return a[i];
 	
  } 
int main()
{
	scanf("%d",&n);
	int dis=sqrt(n);//块的大小
	int num=ceil(1.0*n/dis);//分块的数量
	for(int i=1;i<=n;i++) l[i]=(i-1)*dis+1,r[i]=i*dis;
	r[num]=n;//最后一个块的右端点最大等于n 
	for(int i=1;i<=n;i++)  scanf("%lld",&a[i]),pos[i]=(i-1)/dis+1;
	for(int i=1;i<=n;i++)
	{
		cin>>op>>u>>v>>x;
		if(op==0)
		{
			add(u,v,x);
		}
		else cout<<query(v)<<endl;
	}

}

你可能感兴趣的:(分块)