更优体验请移步CSDN

前言

例题思路分析及代码

首先还是分块的基本操作,每个块长度为\(s\),同时维护每个块内的最大值\(b\)数组

更改

注意到\(C\)的取值范围加了绝对值,就说明\(C\)可能是负数。那么如果修改区间内有最大值,就可能会影响最大值。所以说如果我们不是修改整个块,那么就需要重新统计更改后块的最大值

\(l,r\)同块的无需多言,直接暴力更改,同时重新维护块的最大值。时间复杂度\(O(s)\)

\(l,r\)不同块的还是照样分成三部分,头和尾暴力更改,更新最大值,中间的块给整个区间加上\(C\),同时最大值可以直接加\(C\)(可以简单推理得到)。时间复杂度\(O(\dfrac{n}{s}+s)\)

查询

\(l,r\)同块直接暴力,记得加上给挂在整个块的值

\(l,r\)不同块也是分成三部分,中间部分直接与\(b_i\)进行比较,首尾暴力比较(不要漏掉挂在块上的值)

时间复杂度分析

\(s\)还是取\(\sqrt{n}\)最优,时间复杂度仍然是\(O(n\sqrt{n})\)

Code

#include<cmath>
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
int n,m,len,l,r,x,opt;
ll mx,a[100005],id[100005],b[100005],c[100005];
int read()
{
	int res=0,fh=1;char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') fh=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
	return res*fh;
}
int main()
{
	freopen("max10.in","r",stdin);
	freopen("max10.txt","w",stdout);
	n=read();
	len=sqrt(n);
	for (int i=1;i<=n;++i)
	{
		a[i]=read();
		id[i]=(i-1)/len+1;
		b[id[i]]=max(b[id[i]],a[i]);
	}
	m=read();
	while (m--)
	{
		opt=read();
		if (opt==1)
		{
			l=read();r=read();x=read();
			if (id[l]==id[r])
			{
				for (int i=l;i<=r;++i)
					a[i]+=x;
				b[id[l]]=-2147483647;
				for (int i=(id[l]-1)*len+1;id[i]==id[l];++i)
					b[id[l]]=max(b[id[i]],a[i]+c[id[i]]);
			}
			else
			{
				for (int i=l;id[i]==id[l];++i)
					a[i]+=x;
				for (int i=id[l]+1;i<id[r];++i)
					c[i]+=x,b[i]+=x;
				for (int i=r;id[i]==id[r];--i)
					a[i]+=x;
				b[id[l]]=b[id[r]]=-2147483647;
				for (int i=(id[l]-1)*len+1;id[i]==id[l];++i)
					b[id[l]]=max(b[id[i]],a[i]+c[id[i]]);
				for (int i=(id[r]-1)*len+1;id[i]==id[r];++i)
					b[id[r]]=max(b[id[i]],a[i]+c[id[i]]);
			}
		}
		else
		{
			mx=-2147483647;
			l=read();r=read();
			if (id[l]==id[r])
			{
				for (int i=l;i<=r;++i)
					mx=max(mx,a[i]+c[id[l]]);
			}
			else
			{
				for (int i=l;id[i]==id[l];++i)
					mx=max(mx,a[i]+c[id[l]]);
				for (int i=id[l]+1;i<id[r];++i)
					mx=max(mx,b[i]);
				for (int i=r;id[i]==id[r];--i)
					mx=max(mx,a[i]+c[id[r]]);
			}
			printf("%lld\n",mx);
		}
	}
	return 0;
}

小结

分块其实是一种十分暴力的思想,旨在把区间分割开来,所以说在分块的时候,一定要合理控制块的大小及个数,并不是所有题目\(s\)都是取\(\sqrt{n}\)最优,要根据问题选择合适的\(s\)

另外分块也可以做一些奇奇怪怪的毒瘤题,例如吉司机线段树……

祝大家新年快乐!!!

01-15 05:44