同样是昨天老师讲课讲到的东西,很奇怪以前居然一点也没接触过分块
明明是自己做题太少了喂
于是刷了一下菊苣的分块专题
数列分块入门 1
题目链接
入门无脑题,然而WA了三四发因为把l写成1了,,,被自己气笑了都,,,
对1~n这个区间,按照根号n的长度分为几个区间。
在修改( l , r )区间时,分为两种情况。
1,这段区间在同一个小块内,那么暴力枚举l到r修改这个区间各个元素值即可
2,左右端点不在同一区间,那么把要修改的区间分为三块(或者两块,看中间有没有小块了)暴力修改左端点到左端点所在小块末端和右端点小块头到右端点,对于中间的小块只修改其op值(标记这个区间内的元素要修改但未修改)
输出时候就直接是a[i]+op[i]了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=5e4+10;
#define pi acos(-1.0)
#define INF 0x3f3f3f3f
#define mod 1000000009
#define endll printf("\n")
#define s1(a) scanf("%d",&a)
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
int n,block;//区间长度
int a[MAXN];
int num[MAXN];//每个位置属于哪个块
int op[MAXN];//块上的操作数
void update(int l,int r,int c)
{
for(int i=l;i<=min(num[l]*block,r);i++)
a[i]+=c;
if(num[l]!=num[r])
for(int i=(num[r]-1)*block+1;i<=r;i++)
a[i]+=c;
for(int i=num[l]+1;i<=num[r]-1;i++)
op[i]+=c;
}
int main()
{
s1(n);
mem(op,0);
for(int i=1;i<=n;i++)
s1(a[i]);
block=sqrt(n);
for(int i=1;i<=n;i++)
num[i]=(i-1)/block+1;
for(int i=1;i<=n;i++)
{
int f,l,r,c;
scanf("%d %d %d %d",&f,&l,&r,&c);
if(f)
printf("%d\n",a[r]+op[num[r]]);
else
update(l,r,c);
}
return 0;
}
数列分块入门 2
咕咕咕