Yuuki and a problem
先不管第一问的修改操作,考虑如何达到第二问的查询操作,
题目要我们给出一个区间[l,r][l, r][l,r]中,不能通过权值+++得到的最小的数字是什么,
假设我们已经可以得到[1,x][1, x][1,x]之间的数了,且,我们询问权值在[1,x+1][1, x + 1][1,x+1]之间的和为sumsumsum,那么[1,sum][1, sum][1,sum]之间的数一定能通过+++法得到,
我们分类讨论一下:
- sum=sumxsum = sum_xsum=sumx,显然我们无法合成x+1x + 1x+1了。
- sum≥sumxsum \geq sum_xsum≥sumx,为什么[x+1,sum][x + 1, sum][x+1,sum]之间的数一定可以合成呢?sum=sumx+k(x+1)sum = sum_x + k(x + 1)sum=sumx+k(x+1),我们假定k=1k = 1k=1,由于有前提条件[1,x][1, x][1,x]之间的数是可以合成的,在x+1x + 1x+1的基础上我们可以得到[x+1,x+1+sumx][x + 1, x + 1 + sum_x][x+1,x+1+sumx]之间的数字。
以此每次递增查询,最多就是一个斐波那契数列的形式,所以最多查询不到303030次。
再考虑第一问的修改操作,修改操作,跟区间查询操作连到一起容易想到带修主席树(树状数组套主席树),
整体复杂度30×mlognlogn30 \times m \log n \log n30×mlognlogn。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 2e5 + 10, maxn = 200000;int a[N], n, m;int root[N], ls[N << 7], rs[N << 7], num;ll sum[N << 7];int A[N], B[N], cnt1, cnt2;inline int lowbit(int x) {return x & (-x);
}void update(int &rt, int l, int r, int x, int v) {if (!rt) {rt = ++num;}sum[rt] += v;if (l == r) {return ;}int mid = l + r >> 1;if (x <= mid) {update(ls[rt], l, mid, x, v);}else {update(rs[rt], mid + 1, r, x, v);}
}ll query(int l, int r, int L, int R) {if (l >= L && r <= R) {ll ans = 0;for (int i = 1; i <= cnt1; i++) {ans -= sum[A[i]];}for (int i = 1; i <= cnt2; i++) {ans += sum[B[i]];}return ans;}int mid = l + r >> 1;ll ans = 0;if (L <= mid) {int A1[30], B1[30];for (int i = 1; i <= cnt1; i++) {A1[i] = A[i];A[i] = ls[A[i]];}for (int i = 1; i <= cnt2; i++) {B1[i] = B[i];B[i] = ls[B[i]];}ans += query(l, mid, L, R);for (int i = 1; i <= cnt1; i++) {A[i] = A1[i];}for (int i = 1; i <= cnt2; i++) {B[i] = B1[i];}}if (R > mid) {int A1[30], B1[30];for (int i = 1; i <= cnt1; i++) {A1[i] = A[i];A[i] = rs[A[i]];}for (int i = 1; i <= cnt2; i++) {B1[i] = B[i];B[i] = rs[B[i]];}ans += query(mid + 1, r, L, R);for (int i = 1; i <= cnt1; i++) {A[i] = A1[i];}for (int i = 1; i <= cnt2; i++) {B[i] = B1[i];}}return ans;
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%d %d", &n, &m);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);for (int j = i; j <= n; j += lowbit(j)) {update(root[j], 1, maxn, a[i], a[i]);}}for (int i = 1; i <= m; i++) {int op, x, y;scanf("%d %d %d", &op, &x, &y);if (op & 1) {for (int j = x; j <= n; j += lowbit(j)) {update(root[j], 1, maxn, a[x], -a[x]);}a[x] = y;for (int j = x; j <= n; j += lowbit(j)) {update(root[j], 1, maxn, a[x], a[x]);}}else {cnt1 = cnt2 = 0;for (int j = x - 1; j; j -= lowbit(j)) {A[++cnt1] = root[j];}for (int j = y; j; j -= lowbit(j)) {B[++cnt2] = root[j];}ll cur = 0, sum = 0;do {cur = sum + 1;sum = query(1, maxn, 1, min(cur, 1ll * maxn));}while (sum >= cur);printf("%lld\n", sum + 1);}}return 0;
}