分块:实际上是暴力算法,是优雅的暴力,把区间分成根号n块,保存每个元素所在块,以及块的左右端点,下面是一道模板题,模板来自B站卿学姐。首先是用到的信息。
- b e l o n g [ m a x n ] belong[maxn] belong[maxn] —— 代表每个元素所在的块。
- l [ m a x n ] , r [ m a x n ] l[maxn],r[maxn] l[maxn],r[maxn] —— 代表每一块的左右边界。
-
n
u
m
,
b
l
o
c
k
num,block
num,block —— 代表块的数目,块的大小。
注意的点有:在查询的时候要考虑两个端点是否在同一个分块内、初始化的时候,要考虑最后一个分块的右端点是否超出n。
题目:当点修改+查询区间最大值。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5+7;
int belong[maxn],num,l[maxn],r[maxn],block,n,q;
ll Max[maxn],a[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;
r[num] = n;
for(int i=1;i<=n;i++)belong[i] = (i-1)/block+1; //计算i属于哪一块
for(int i=1;i<=num;i++) //更新块内答案
for(int j=l[i];j<=r[i];j++)
Max[i] = max(a[j],Max[i]);
}
void up(int x,int y)
{
a[x] += y;
Max[belong[x]] = max(a[x],Max[belong[x]]);
}
long long qu(int x,int y)
{
ll ans = 0;
if(belong[x] == belong[y]) //特判是否在同一块
{
for(int i=x;i<=y;i++)ans=max(ans,a[i]);
return ans;
}
for(int i=x;i<=r[belong[x]];i++)ans = max(a[i],ans);
for(int i=belong[x]+1;i<belong[y];i++)ans = max(ans,Max[i]);
for(int i=l[belong[y]];i<=y;i++)ans = max(ans,a[i]);
return ans;
}
int main()
{
scanf("%d%d",&n,&q);
while(q--)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op == 1)up(x,y);
else printf("%lld\n",qu(x,y));
}
return 0;
}