分块

一、区间查询+单点更新
luogu3374
已知一个数列,你需要进行下面两种操作:1.将某一个数加上x;2.求出某区间每一个数的和(luogu3374)

#include<bits/stdc++.h>
using namespace std;
#define maxn 500010

int n,m;
int num,block;//block块的大小,num分块的个数

int belong[maxn],l[maxn],r[maxn];
//belong[i]表示i属于哪一块
//l[i]表示i这块的左端点位置
//r[i]表示右端点位置
int a[maxn],mark[maxn];
int nana[maxn];//表示该块的和 

void build()
{
	block=sqrt(n);
	num=n/block;
	if(n%block)num++;
	
	for (int i=1;i<=num;i++)
	{
		l[i]=(i-1)*block+1;
		r[i]=i*block;
	}//存每一块的左右端点 
		
	for (int i=1;i<=n;i++)//存分区
		belong[i]=(i-1)/block+1;
		
	for (int i=1;i<=n;i++)//求每一块的总和 
		nana[belong[i]]+=a[i];
}
//单点更新 
void update(int pos,int x)
{
	nana[belong[pos]]+=x;
	a[pos]+=x;
}
//区间查询 
void query(int L,int R)
{
	int ans=0;
	
	if (belong[L]==belong[R])//l,r在同一块 
	{
		for (int i=L;i<=R;i++)
			ans+=a[i];
		printf("%d\n",ans);
		return;
	}
	
	for (int i=L;i<=r[belong[L]];i++)//左不完整块 
		ans+=a[i];
	
	for (int i=l[belong[R]];i<=R;i++)//右不完整块 
		ans+=a[i];
	
	for (int i=belong[L]+1;i<belong[R];i++)//中间的完整块 
		ans+=nana[i];
		
	printf("%d\n",ans);
}

int main()
{
	
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	build();
	int  flag,x,y;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&flag,&x,&y);
		if (flag==2)query(x,y);
		else update(x,y);
	}
	
	return 0;
} 

二、区间更新+单点查询
luogu3368
已知一个数列,你需要进行下面两种操作:1.将某区间每一个数数加上x;2.求出某一个数的和

#include<bits/stdc++.h>
using namespace std;
#define maxn 500010

int n,m;
int num,block;//block块的大小,num分块的个数
int belong[maxn],l[maxn],r[maxn];
//belong[i]表示i属于哪一块
//l[i]表示i这块的左端点位置
//r[i]表示右端点位置
int a[maxn],mark[maxn];
int nana[maxn];//表示该块的和 

void build()
{
	block=sqrt(n);
	num=n/block;
	if(n%block)num++;
	
	for (int i=1;i<=num;i++)
	{
		l[i]=(i-1)*block+1;
		r[i]=i*block;
	}//存每一块的左右端点 
		
	for (int i=1;i<=n;i++)//存分区
		belong[i]=(i-1)/block+1;
}
//区间加法 
void several_add(int L,int R,int k)
{
    for(int i=L;i<=r[belong[L]];i++)
        a[i]+=k;
    if(belong[L]!=belong[R])
        for(int i=l[belong[R]];i<=R;i++)
            a[i]+=k;
    for(int i=belong[L]+1;i<=belong[R]-1;i++)
        nana[i]+=k;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	build();
	int  flag,x,y;
	for (int i=1;i<=m;i++)
	{
		scanf("%d",&flag);
		
		if (flag==2)
		{
			int K;
			scanf("%d",&K);
			printf("%d\n",a[K]+nana[belong[K]]);
		}
		else
		{
			int x,y,k;
			scanf("%d %d %d",&x,&y,&k);
			several_add(x,y,k);
		}
	}
	return 0;
} 

三、区间加法+区间乘法+区间点查询
luogu3373
已知一个数列,你需要进行下面三种操作:1.将某区间每一个数加上x;2.将某区间每一个数乘上x;3.求出某区间每一个数的和。

上一篇:跟着专注于计算机视觉的AndyJ的妈妈我学算法之每日一题leetcode33搜索旋转排序数组


下一篇:神奇的莫队