题解:P13978 数列分块入门 3
LostKeyToReach · · 题解
去年做了这道题开始熟悉分块的。
考虑对序列分块,
对于加法操作,直接散块暴力加,整块对
考虑怎么查询,散块可以直接暴力。但是整块不好维护,因为你要维护满足
时间复杂度
// author : LostKeytoReach
// submitted time : 2024 - 07 - 29 on LibreOJ
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#define pb push_back
#define all(x) x.begin(), x.end()
#define int long long
using namespace std;
typedef long long ll;
ll n, a[200006];
ll sum[200006], tag[200006];
int id[200006], block, mxn;
vector <ll> p[2000006];
ll find(int x, ll val) {
int ans = -1, l = 0, r = (int)p[x].size() - 1;
while (l <= r) {
int mid = l + r >> 1;
if (p[x][mid] < val)
ans = mid, l = mid + 1;
else
r = mid - 1;
}
return ans;
}
void reset(int x) {
p[x].clear();
int up = (x - 1) * block + 1;
for (int i = up; id[i] == x; i++) {
p[x].pb(a[i]);
}
sort(all(p[x]));
}
void modify(int l, int r, ll v) {
int lid = id[l], rid = id[r];
if (lid == rid) {
for (int i = l; i <= r; i++) {
a[i] += v;
}
reset(lid);
return;
}
for (int i = l; id[i] == lid; i++) {
a[i] += v;
}
reset(lid);
for (int i = lid + 1; i < rid; i++) {
tag[i] += v;
}
for (int i = r; id[i] == rid; i--) {
a[i] += v;
}
reset(rid);
}
ll query(int l, int r, ll v) {
int lid = id[l], rid = id[r];
ll ans = -1e18;
if (lid == rid) {
for (int i = l; i <= r; i++) {
if (a[i] + tag[lid] < v) {
ans = max(ans, a[i] + tag[lid]);
}
}
return (ans == -1e18 ? -1 : ans);
}
for (int i = l; id[i] == lid; i++) {
if (a[i] + tag[lid] < v) {
ans = max(ans, a[i] + tag[lid]);
}
}
for (int i = lid + 1; i < rid; i++) {
int pos = find(i, v - tag[i]);
if (pos >= 0) {
ans = max(ans, p[i][pos] + tag[i]);
}
}
for (int i = r; id[i] == rid; i--) {
if (a[i] + tag[rid] < v) {
ans = max(ans, a[i] + tag[rid]);
}
}
return (ans == -1e18 ? -1 : ans);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
block = sqrt(n);
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[id[i] = (i - 1) / block + 1] += a[i];
}
for (int i = 1; i <= n; i++) {
p[id[i]].pb(a[i]);
}
mxn = *max_element(id + 1, id + n + 1);
for (int i = 1; i <= mxn; i++)
sort(all(p[i]));
for (int lxl = 1; lxl <= n; lxl++) {
ll o, l, r, x;
cin >> o >> l >> r >> x;
if (o == 0) {
modify(l, r, x);
} else {
cout << query(l, r, x) << '\n';
}
}
}