数列分块入门 3 题解
Posted lajiccf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数列分块入门 3 题解相关的知识,希望对你有一定的参考价值。
vector+块内二分。
修改时需要重构,查询时可以二分查出来。
不要忘记 add 标记!
#pragma GCC diagnostic error "-std=c++14"
#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
int n,bl,m,opt,l,r,v;
int a[100010], pos[100010], add[100010],L[100010],R[100010];
vector<int> b[100010];
void reset(int x) {
b[x].clear();
for(int i=L[x]; i<=R[x]; i++)
b[x].push_back(a[i]+=add[x]);
sort(b[x].begin(),b[x].end());
add[x]=0;
return;
}//对第 x 块进行重构,并加上标记
void update(int l, int r, int v) {
if(pos[l]==pos[r]) {
for(int i=l; i<=r; i++)
a[i]+=v;
reset(pos[l]);
return;
}
for(int i=l; i<=R[pos[l]]; i++)
a[i]+=v;
reset(pos[l]);
for(int i=L[pos[r]]; i<=r; i++)
a[i]+=v;
reset(pos[r]);
for(int i=pos[l]+1; i<=pos[r]-1; i++)
add[i]+=v;
return;
}
int query(int l, int r, int v) {
int ans=-1;
if(pos[l]==pos[r]) {
for(int i=l; i<=r; i++)
if(a[i]+add[pos[i]]<v)
ans=max(ans,a[i]+add[pos[i]]);
return ans;
}
for(int i=l;i<=R[pos[l]];i++)
if(a[i]+add[pos[i]]<v)
ans=max(ans,a[i]+add[pos[i]]);
for(int i=L[pos[r]];i<=r;i++)
if(a[i]+add[pos[i]]<v)
ans=max(ans,a[i]+add[pos[i]]);
for(int i=pos[l]+1;i<=pos[r]-1;i++) {
int kk=lower_bound(b[i].begin(),b[i].end(),v-add[i])-b[i].begin();
if(kk>0)
ans=max(ans,b[i][kk-1]+add[i]);//二分查找
}
return ans;
}
int main() {
scanf("%d", &n);
bl = sqrt(n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
pos[i] = (i - 1) /bl + 1;
b[pos[i]].push_back(a[i]);
}
for(int i=1; i<=pos[n]; i++)
L[i]=(i-1)*bl+1,R[i]=i*bl;
R[pos[n]]=n;
for(int i=1; i<=pos[n]; i++)
sort(b[i].begin(),b[i].end());
for (int i = 1; i <= n; i++) {
int ch;
int x, y, v;
scanf("%d %d %d %d", &ch, &x, &y, &v);
if (ch == 0)
update(x, y, v);
else
printf("%d
", query(x, y, v));
}
return 0;
}
以上是关于数列分块入门 3 题解的主要内容,如果未能解决你的问题,请参考以下文章