题意:给你一个序列,每次操作可以使一段连续的序列加1,每次更新完后输出这个序列的中位数。
注意到中位数的大小只会增加,不会减小,并且每次操作后最多使中位数加1.
将原序列分块操作,若块在询问的【L,R】中,则使块的cnt++,这样只对询问区间的首尾单独操作即可。
每次更新后查找序列中小于等于当前中位数的个数,如果个数小于等于n/2.则中位数++。
查找小于等于中位数的个数时用lower_bound会超时,可以存一个计数器p表示更新前的个数,因为大部分的区间p值不会改变。(但是最坏复杂度大了很多= =)
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson o<<1
#define rson o<<1|1
#define CLR(A, X) memset(A, X, sizeof(A))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const double eps = 1e-10;
int dcmp(double x){if(fabs(x)<eps) return 0; return x<0?-1:1;}
const int N = 6e4+5;
struct node {
int len, cnt, p;
PII a[300];
void clear() { len = cnt = p = 0; }
void push_back(int x, int y) { a[len++] = {x, y}; }
void my_sort() { sort(a, a+len); }
void update(int L, int R) {
for(int i = 0; i < len; i++) {
if(a[i].se<=R && a[i].se>=L) {
a[i].fi++;
}
}
my_sort();
}
int sum(int x) {
while(p>=0 && a[p].fi+cnt>x) p--;
while(p+1<len && a[p+1].fi+cnt<=x) p++;
return p+1;
}
}b[300];
int a[N];
int main() {
int n, q, x;
while(~scanf("%d%d", &n, &q)) {
if(!n && !q) continue;
int len = sqrt(n+0.5), tot = n/len+!!(n%len);
for(int i = 0; i < tot; i++) b[i].clear();
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
b[i/len].pb(a[i], i);
}
for(int i = 0; i < tot; i++) b[i].my_sort();
sort(a, a+n);
int Mid = a[n/2];
while(q--) {
int L, R;
scanf("%d%d", &L, &R);
L--, R--;
for(int i = L/len+1; i < R/len; i++) b[i].cnt++;
if(L/len == R/len) b[L/len].update(L, R);
else {
b[L/len].update(L, (L/len+1)*len-1);
b[R/len].update((R/len)*len, R);
}
int tmp = 0;
for(int i = 0; i < tot; i++) {
tmp += b[i].sum(Mid);
}
if(tmp <= n/2) Mid++;
printf("%d\n", Mid);
}
}
return 0;
}