Most Influential Pumpkin
题意
给 (n) 个元素的数组 (A) ,(k) 次操作,每次操作使得区间 ([L_i,R_i]) 内的数加 1,每次操作后你都要输出当前 (A) 数组的中位数。
(1 le n,k le 6e4) , (n) 是奇数
思路
因为每次只进行加一操作,所以答案只可能是上一次的答案或者上一次的答案加 1.
开一个数组 (B) ,初始化 (B=A) ,然后将 (B) 分块,使得 (B) 在块内有序。先处理出初始中位数 (Ans)
对于每一次操作,小块里的直接暴力修改 (A) ,然后暴力重构 (B) ,对于连续的完整块,开一个标记数组 (tag) 表示该块全体增加了多少。
对于每一次的答案,我们可以询问 (B) 内小于等于 (Ans) 的数的个数,若小于 (lceil dfrac n 2 ceil) 则 (Ans) 加 1. ((O(sqrt nlogsqrt n)))
/*
* @Author: zhl
* @LastEditTime: 2021-03-10 21:36:31
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, A[N], id[N], B[N], l[N], r[N], tag[N];
void block_sort(int idx) {
for (int i = l[idx];i <= r[idx];i++)B[i] = A[i];
sort(B + l[idx], B + r[idx] + 1);
}
void build() {
int len = sqrt(n);
for (int i = 1;i <= n;i++)id[i] = (i + len - 1) / len;
for (int i = id[1];i <= id[n];i++) {
l[i] = len * (i - 1) + 1;
r[i] = len * i;
tag[i] = 0;
}
r[id[n]] = n;
for (int i = id[1];i <= id[n];i++)block_sort(i);
}
void updt(int L, int R) {
for (int idx = id[L] + 1;idx <= id[R] - 1;idx++)tag[idx]++;
if (id[L] == id[R]) {
for (int i = L;i <= R;i++)A[i]++;
block_sort(id[L]);
}
else {
for (int i = L;i <= r[id[L]];i++)A[i]++;
block_sort(id[L]);
for (int i = l[id[R]];i <= R;i++)A[i]++;
block_sort(id[R]);
}
}
int cal(int v) {
int res = 0;
for (int idx = id[1];idx <= id[n];idx++) {
res += upper_bound(B + l[idx], B + r[idx] + 1, v - tag[idx]) - (B + l[idx]);
}
return res;
}
int main() {
#ifdef ONLINE_JUDGE
freopen("f.in", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
while (~scanf("%d%d", &n, &m) and n + m) {
for (int i = 1;i <= n;i++)scanf("%d", A + i), B[i] = A[i];
int mid = (n + 1) / 2;
sort(B + 1, B + 1 + n);
int ans = B[mid];
build();
for (int i = 1, L, R;i <= m;i++) {
scanf("%d%d", &L, &R);
updt(L, R);
if (cal(ans) < mid)ans++;
printf("%d
", ans);;
}
}
}
/*
1 1
1
1 1
3 4
3 2 1
1 3
1 1
3 3
3 3
0 0
7 7
1 1 1 3 3 3 3
1 3
5 7
1 3
1 4
1 3
4 4
1 3
0 0
*/