「Template」整體二分
阿新 • • 發佈:2022-02-17
帶修的區間第 \(k\) 小。
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define LL long long #define rep(i, j, k) for(int i = (j); i <= (k); i ++) #define per(i, j, k) for(int i = (j); i >= (k); i --) const int Maxn = 1e5; int n, m, tot; char s[2]; int a[Maxn + 5], ans[Maxn + 5], Bit[Maxn + 5]; struct Node { int l, r, k, id, opt; } q[Maxn * 3 + 5]; queue < Node > q1, q2; namespace BIT { void Update (int x, int y) { for (int i = x; i <= n; i += i & -i) Bit[i] += y; } int Sum (int x) { int sum = 0; for (int i = x; i; i -= i & -i) sum += Bit[i]; return sum; } } using namespace BIT; void Solve (int ql, int qr, int l, int r) { //當前處理的操作區間為 [ql,qr] ,值域區間為 [l,r] if (ql > qr) return ; if (l == r) { //找到答案 rep (i, ql, qr) { if (q[i].opt == 0) ans[q[i].id] = l; //對於[ql,qr] 中的查詢操作更新答案 } return ; } int mid = (l + r) >> 1; //二分 rep (i, ql, qr) { if (q[i].opt == 0) { //屬於查詢操作 int sum = Sum (q[i].r) - Sum (q[i].l - 1); //進行了[ql,i-1]操作後,[q[i].l,q[i].r](查詢的區間)中小於 mid 的數的個數 if (sum >= q[i].k) { //若個數大於詢問的 k ,代表詢問的答案小於 mid (答案更小才能讓sum變小最終等於k),答案在[l,mid] q1.push (q[i]); //放入[l,mid]的陣列 } else { //否則,答案在[mid+1,r] q[i].k -= sum; //減去[ql,i-1]操作中小於mid的數對答案排名產生的貢獻 q2.push (q[i]); //放入[mid+1,r]的陣列 } } else { //屬於 刪除 / 插入 if (q[i].k <= mid) { //元素大小小於 mid Update (q[i].id, q[i].opt); //根據 opt 新增/刪除 其產生的貢獻 q1.push (q[i]); //對於[l,mid]中的答案可能會產生貢獻 } else { q2.push (q[i]); //對於[mid+1,r]中的答案可能會產生貢獻 } } } int pos = ql - 1; while (q1.size ()) { Node res = q1.front (); if (res.opt) Update (res.id, -res.opt); //撤銷 q[++ pos] = res; q1.pop (); } int now = pos; //以 now 為分界 while (q2.size ()) { q[++ pos] = q2.front (); q2.pop (); } Solve (ql, now, l, mid); Solve (now + 1, qr, mid + 1, r); //遞迴 } int main () { scanf ("%d %d", &n, &m); rep (i, 1, n) { scanf ("%d", &a[i]); q[++ tot] = {0, 0, a[i], i, 1}; //將初始的陣列看成插入元素 } rep (i, 1, m) { scanf ("%s", s + 1); switch (s[1]) { case 'Q' : { int l, r, k; scanf ("%d %d %d", &l, &r, &k); q[++ tot] = {l, r, k, i, 0}; //查詢操作 break; } case 'C' : { int x, y; scanf ("%d %d", &x, &y); //將修改拆成 刪除+插入 q[++ tot] = {0, 0, a[x], x, -1}; //刪除 a[x] = y; //更新一下 q[++ tot] = {0, 0, a[x], x, 1}; //插入 break; } } } memset (ans, -1, sizeof ans); Solve (1, tot, -1e9, 1e9); rep (i, 1, m) { if (~ans[i]) printf ("%d\n", ans[i]); } return 0; }