😊 | Powered By HeartFireY | 分块例题

​#6279. 数列分块入门 3 - 题目 - LibreOJ (loj.ac)​

与上一题极为相似。(​​数列分块入门 2​​)

对于区间加操作:采取与上题相同的方式,非完整块暴力取出修改放回,完整块直接打标记

对于查询操作:

  • 对于头尾块,直接遍历查询小于待查值的最大值,查询过程不断取3.数列分块入门 3_acm竞赛
  • 对于完整块,二分一个大于等于待查值的最小位置,然后3.数列分块入门 3_算法_02可得答案位置。这里的二分可以直接采用3.数列分块入门 3_数据结构_033.数列分块入门 3_分块_04
#include <bits/stdc++.h>
using namespace std;

const int N = 5e5 + 10;
int id[N], blo, n;
int a[N], tag[N];

vector<int> block[N];

void update(int loc){
block[loc].clear();
for(int i = (loc - 1) * blo + 1; i <= min(loc * blo, n); i++) block[loc].push_back(a[i]);
sort(block[loc].begin(), block[loc].end());
}

void add(int l, int r, int v){
for(int i = l; i <= min(id[l] * blo, r); i++) a[i] += v;
update(id[l]);
if(id[l] == id[r]) return;
for(int i = (id[r] - 1) * blo + 1; i <= r; i++) a[i] += v;
update(id[r]);
for(int i = id[l] + 1; i <= id[r] - 1; i++) tag[i] += v;
}

int query(int l, int r, int k, int ans = -1){
for(int i = l; i <= min(id[l] * blo, r); i++)
if(a[i] + tag[id[l]] < k) ans = max(ans, a[i] + tag[id[l]]);
if(id[l] == id[r]) return ans;
for(int i = (id[r] - 1) * blo + 1; i <= r; i++)
if(a[i] + tag[id[r]] < k) ans = max(ans, a[i] + tag[id[r]]);
for(int i = id[l] + 1; i <= id[r] - 1; i++){
int tmp = k - tag[i];
int pos = lower_bound(block[i].begin(), block[i].end(), tmp) - block[i].begin();
if(pos >= 1) ans = max(ans, block[i][pos - 1] + tag[i]);
}
return ans;
}

signed main(){
ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n; blo = sqrt(n * 1.0);
for(int i = 1; i <= n; i++){
cin >> a[i];
id[i] = (i - 1) / blo + 1;
block[id[i]].push_back(a[i]);
}
for(int i = 1; i <= id[n]; i++) sort(block[i].begin(), block[i].end());
for(int i = 1; i <= n; i++){
int op, l, r, v; cin >> op >> l >> r >> v;
if(op == 0) add(l, r, v);
else if(op == 1) cout << query(l, r, v) << endl;
}
return 0;
}