Problem - E - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1705/problem/E给你n个数的序列,再给你m个操作,每次操作给出你两个数k,x
将第k个数改为x,并问你改完之后可以选择出现2次的数合并为该数+1的数,求完成这些操作后序列的最大值。
假设某一个数是x,若有出现两次以上的x,那么我们就可以合并为x+1,可以想到二进制加法,当一个二进制数为00011,若第一位+1,则该数变为00100,跟我们上面的情况一样,所以我们可以将其转化为二进制加法,然后用线段树维护。
const int N = 2e5 + 106;
struct node {
int l, r;
int add;
int sum;
} tr[MAXN * 3];
int cnt[MAXN], a[MAXN];
void push_up(int q) {
tr[q].sum = tr[q << 1].sum + tr[q << 1 | 1].sum;
}
void update(int q, int add) {
tr[q].sum += (tr[q].r - tr[q].l + 1) * add;
tr[q].add += add;
}
void push_down(int q) {
if (tr[q].add) {
update(q << 1, tr[q].add), update(q << 1 | 1, tr[q].add);
tr[q].add = 0;
}
}
void build(int q, int l, int r) {
tr[q].l = l, tr[q].r = r;
if (l == r)
return void(tr[q].sum = cnt[r]);
int mid = l + r >> 1;
build(q << 1, l, mid);
build(q << 1 | 1, mid + 1, r);
push_up(q);
}
void modify(int q, int l, int r, int add) {
// printf("2\n");
if (tr[q].l >= l && tr[q].r <= r) {
update(q, add);
return;
}
push_down(q);
int mid = tr[q].l + tr[q].r >> 1;
if (l <= mid)
modify(q << 1, l, r, add);
if (r > mid)
modify(q << 1 | 1, l, r, add);
push_up(q);
}
int query0(int q, int l) {
// printf("3\n");
if (tr[q].r < l || tr[q].sum == tr[q].r - tr[q].l + 1)
return -1;
if (tr[q].l == tr[q].r)
return tr[q].r;
push_down(q);
int t = query0(q << 1, l);
if (~t)
return t;
return query0(q << 1 | 1, l);
}
int query1(int q, int l) {
// printf("4\n");
if (tr[q].r < l || !tr[q].sum)
return -1;
if (tr[q].l == tr[q].r)
return tr[q].r;
push_down(q);
int t = query1(q << 1, l);
if (~t)
return t;
return query1(q << 1 | 1, l);
}
int querymax(int q) {
// printf("5\n");
if (tr[q].l == tr[q].r)
return tr[q].r;
push_down(q);
if (tr[q << 1 | 1].sum)
return querymax(q << 1 | 1);
return querymax(q << 1);
}
int query(int q, int x) {
if (tr[q].l == tr[q].r)
return tr[q].r;
push_down(q);
int mid = tr[q].l + tr[q].r >> 1;
if (x <= mid)
return query(q << 1, x);
return query(q << 1 | 1, x);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[a[i]]++;
}
for (int i = 1; i <= N; i++) {
cnt[i + 1] += cnt[i] / 2;
cnt[i] %= 2;
}
build(1, 1, N);
while (m--) {
int k, x;
cin >> k >> x;
int pos = query1(1, a[k]);
modify(1, pos, pos, -1);
if (pos != a[k])
modify(1, a[k], pos - 1, 1);
a[k] = x;
// printf("===\n");
pos = query0(1, a[k]);
modify(1, pos, pos, 1);
if (pos != a[k])
modify(1, a[k], pos - 1, -1);
cout << querymax(1) << '\n';
}
return 0;
}