简单分块1

数列分块1

题目描述

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

大家很容易会想到差分。但题目的单点查询是在线查询(修改操作和查询操作是穿插在一起的,立刻回答)而差分是离线的(全部打完标记后,再求前缀和。把所有修改操作全做完了,再全部回答)如果差分在线做的,复杂度很高,要不停求前缀和

 

所以这就要用分块了!

分块:优雅的暴力

我们先把数列切成√n块,那每一块就是√n,一共是n块。a数组是原始数组,b数组是用来打标记的。

分块口诀:大段维护,小段暴力。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll read()//快读
{
    ll x=0,f=1;
	char ch=getchar();
    while(!isdigit(ch))
	{  
	  if(ch=='-') f=-1;
	  ch=getchar();
	}
    while(isdigit(ch))
	{
	 x=x*10+ch-'0';
	 ch=getchar();
	}
    return x*f;
}

int n,blo;
int v[50005],bl[50005],atag[50005];

void add(int a,int b,int c)//大段维护,小段暴力
{
    for(int i=a;i<=min(bl[a]*blo,b);i++)//左端点所在的右边界 bl[a]左端点所在的块号*块的大小
        v[i]+=c;//暴力加法
    
	if(bl[a]!=bl[b])//如果a块和b块不相同
      for(int i=(bl[b]-1)*blo+1;i<=b;i++)//b所在的左端点到b
         v[i]+=c;//暴力加法
    
	for(int i=bl[a]+1;i<=bl[b]-1;i++)//a、b之间的完整大块
        atag[i]+=c;//打标记
}

int main()
{
    n=read();
	blo=sqrt(n);//每一块大小√n
    
	for(int i=1;i<=n;i++)
	   v[i]=read();
    
	for(int i=1;i<=n;i++)
	   bl[i]=(i-1)/blo+1;//元素属于哪一块
    
	for(int i=1;i<=n;i++)
    {
        int f=read(),a=read(),b=read(),c=read();//一系列查询  a~b区间
        if(f==0) add(a,b,c);//区间统一增加
        if(f==1) printf("%d\n",v[b]+atag[bl[b]]);//单点查询 原来的值v[b]加上一系列打上的标记
    }
    
    return 0;
}

写作不易,麻烦动手点个赞,再走,行不?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值