P5356 [Ynoi2017] 由乃打扑克

题目链接

思路:
  实现两个操作,区间加法和查询区间第k大。考虑分块的做法,区间加法对整块来说可以直接另开一个数组tag来对整块进行区间加法,对于零散块就直接暴力的加上。

区间加法
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; } }
查询区间第k大,要用二分来快速的查找,我们对查询区间的所有数字进行二分答案,查询此时二分的值是不是第k大,如果比k大那就重新定上界,如果比k小就重新定下界。对于零散块内大于mid的值的计算可以直接暴力,对于整块的计算可能不太好处理,所以要预处理出来一个块内排序好了的数组b,这样我们对块内的计算就分类讨论

  1.块内最大的元素小于mid
  2.块内最小的元素大于mid
  3.块内最大的元素大于mid,块内最小的元素小于mid,对于这种情况我们二分处理。

查询区间第k
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; }

全部的代码:

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__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16580020.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示