思路:
实现两个操作,区间加法和查询区间第k大。考虑分块的做法,区间加法对整块来说可以直接另开一个数组tag来对整块进行区间加法,对于零散块就直接暴力的加上。
区间加法
查询区间第k大,要用二分来快速的查找,我们对查询区间的所有数字进行二分答案,查询此时二分的值是不是第
k大,如果比
k大那就重新定上界,如果比
k小就重新定下界。对于零散块内大于
mid的值的计算可以直接暴力,对于整块的计算可能不太好处理,所以要预处理出来一个块内排序好了的数组
b,这样我们对块内的计算就分类讨论
1.块内最大的元素小于mid
2.块内最小的元素大于mid
3.块内最大的元素大于mid,块内最小的元素小于mid,对于这种情况我们二分处理。
查询区间第k大
全部的代码:
constexpr int N = 1000010;
constexpr int M = 150;
int n, m;
int bln[N], brn[N], belong[N];
i64 tag[N];
i64 a[N], b[N];
void update(int l, int r, i64 x) {
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i++ )
a[i] += x;
for (int i = bln[belong[l]], bel = belong[l]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
std::sort(b + bln[belong[l]], b + brn[belong[l]] + 1);
return ;
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
a[i] += x;
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
a[i] += x;
}
for (int i = bln[belong[l]], bel = belong[l]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
for (int i = bln[belong[r]], bel = belong[r]; i <= brn[bel]; i++ ) {
b[i] = a[i];
}
std::sort(b + bln[belong[l]], b + brn[belong[l]] + 1);
std::sort(b + bln[belong[r]], b + brn[belong[r]] + 1);
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
tag[i] += x;
}
}
i64 MAX(int l, int r) {
i64 res = std::numeric_limits<int>::min();
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i ++ )
res = std::max(res, a[i] + tag[belong[l]]);
return res;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
res = std::max(res, b[brn[i]] + tag[i]);
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
res = std::max(res, a[i] + tag[bel]);
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
res = std::max(res, a[i] + tag[bel]);
}
return res;
}
i64 MIN(int l, int r) {
i64 res = std::numeric_limits<int>::max();
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i ++ )
res = std::min(res, a[i] + tag[belong[l]]);
return res;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
res = std::min(res, b[bln[i]] + tag[i]);
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
res = std::min(res, a[i] + tag[bel]);
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
res = std::min(res, a[i] + tag[bel]);
}
return res;
}
i64 check(int l, int r, i64 x) {
i64 cnt = 0;
if (belong[l] == belong[r]) {
for (int i = l; i <= r; i++ ) {
cnt += (a[i] + tag[belong[i]] <= x);
}
return cnt;
}
for (int i = belong[l] + 1; i < belong[r]; i++ ) {
if (b[bln[i]] + tag[i] > x) continue;
if (b[brn[i]] + tag[i] <= x) {
cnt += brn[i] - bln[i] + 1;
continue;
}
int ln = bln[i], rn = brn[i];
while(ln < rn) {
int mid = (ln + rn + 1) >> 1;
if (b[mid] + tag[i] <= x) ln = mid;
else rn = mid - 1;
}
if (b[ln] + tag[i] <= x) cnt += ln - bln[i] + 1;
}
for (int i = l, bel = belong[l]; i <= brn[bel]; i++ ) {
if (a[i] + tag[bel] <= x) cnt ++;
}
for (int i = bln[belong[r]], bel = belong[r]; i <= r; i++ ) {
if (a[i] + tag[bel] <= x) cnt ++;
}
return cnt;
}
int query(int l, int r, int k) {
if (k < 1 || k > r - l + 1) return -1;
int ans = -1;
i64 ln = MIN(l, r);
i64 rn = MAX(l, r);
while(ln <= rn) {
i64 mid = (ln + rn) >> 1;
if (check(l, r, mid) < k) ln = mid + 1;
else rn = mid - 1, ans = mid;
}
return ans;
}
signed main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cin >> n >> m;
for (int i = 1; i <= n; i ++ ) {
std::cin >> a[i];
b[i] = a[i];
belong[i] = (i - 1) / M + 1;
}
int lim = std::ceil(n * 1.0 / M);
for (int i = 1; i <= lim; i ++ ) {
bln[i] = (i - 1) * M + 1, brn[i] = i * M;
}
brn[lim] = n;
for (int i = 1; i <= lim; i++ )
std::sort(b + bln[i], b + brn[i] + 1);
for (int i = 0; i < m; i++ ) {
int op, l, r, k;
std::cin >> op >> l >> r >> k;
if (op == 1) std::cout << query(l, r, k) << "\n";
else update(l, r, k);
}
return 0 ^ 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~