[BZOJ 3110] [ZJOI 2013] K大数查询

Description

\(N\) 个位置,\(M\) 个操作。操作有两种,每次操作如果是:

  • 1 a b c:表示在第 \(a\) 个位置到第 \(b\) 个位置,每个位置加入一个数 \(c\)
  • 2 a b c:表示询问从第 \(a\) 个位置到第 \(b\) 个位置,第 \(c\) 大的数是多少。

Input

第一行 \(N, M\)

接下来 \(M\) 行,每行形如 1 a b c 或 2 a b c。

Output

输出每个询问的结果。

Sample Input

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

Sample Output

1
2
1

HINT

\(N,M\le50000\)

\(1\) 操作中 \(|c|\le N\)

\(2\) 操作中 \(|c|\le \text{maxlongint}\)

Solution

首先,操作一是给 \([a,b]\) 的每个位置插入一个数 \(c\),每个位置可以有多个数。(我一直以为是区间加QAQ。)

Solve(l, r, L, R) 表示第 \([L,R]\) 个询问可能的答案在区间 \([l,r]\) 中。每次把 \(c\le mid\) 的插入操作放到左边,把 \(c>mid\) 的放到右边;把答案在 \([l,mid]\) 的询问放到左边,把答案在 \([mid+1,r]\) 的询问放到右边。时间复杂度 \(O(n\log^2n)\)

Code

#include <cstdio>

const int N = 50005;
typedef long long LL;
struct Node { int l, r, x, f; LL k; } a[N], b[N], c[N];
int ans[N], n, m, cnt; LL tag[N << 3], sum[N << 3];

int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x * f;
}
void pushdown(int cur, int l, int r) {
    int mid = (l + r) >> 1;
    tag[cur << 1] += tag[cur], tag[cur << 1 | 1] += tag[cur];
    sum[cur << 1] += tag[cur] * (mid - l + 1), sum[cur << 1 | 1] += tag[cur] * (r - mid);
    tag[cur] = 0;
}
void update(int cur, int l, int r, int L, int R, int x) {
    if (L <= l && r <= R) { tag[cur] += x, sum[cur] += x * (r - l + 1); return; }
    if (tag[cur]) pushdown(cur, l, r);
    int mid = (l + r) >> 1;
    if (L <= mid) update(cur << 1, l, mid, L, R, x);
    if (mid < R) update(cur << 1 | 1, mid + 1, r, L, R, x);
    sum[cur] = sum[cur << 1] + sum[cur << 1 | 1];
}
LL query(int cur, int l, int r, int L, int R) {
    if (L <= l && r <= R) return sum[cur];
    if (tag[cur]) pushdown(cur, l, r);
    int mid = (l + r) >> 1; LL res = 0;
    if (L <= mid) res = query(cur << 1, l, mid, L, R);
    if (mid < R) res += query(cur << 1 | 1, mid + 1, r, L, R);
    return res;
}
void solve(int l, int r, int L, int R) {
    if (l > r || L > R) return;
    if (l == r) {
        for (int i = L; i <= R; ++i) if (a[i].f) ans[a[i].x] = n - l + 1;
        return;
    }
    int mid = (l + r) >> 1, p = 0, q = 0;
    for (int i = L; i <= R; ++i)
        if (a[i].f) {
            LL tmp = query(1, 1, n, a[i].l, a[i].r);
            if (tmp >= a[i].k) b[++p] = a[i];
            else a[i].k -= tmp, c[++q] = a[i];
        } else {
            if (a[i].k <= mid) update(1, 1, n, a[i].l, a[i].r, 1), b[++p] = a[i];
            else c[++q] = a[i];
        }
    for (int i = 1; i <= p; ++i) if (!b[i].f) update(1, 1, n, b[i].l, b[i].r, -1);
    for (int i = 1; i <= p; ++i) a[L + i - 1] = b[i];
    for (int i = 1; i <= q; ++i) a[L + p + i - 1] = c[i];
    solve(l, mid, L, L + p - 1), solve(mid + 1, r, L + p, R);
}
int main() {
    n = read(), m = read();
    for (int i = 1; i <= m; ++i) {
        int op = read(), x = read(), y = read(); LL z; scanf("%lld", &z);
        if (op == 1) a[i] = (Node){x, y, i, 0, n - z + 1};
        else a[i] = (Node){x, y, ++cnt, 1, z};
    }
    solve(1, n, 1, m);
    for (int i = 1; i <= cnt; ++i) printf("%d\n", ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fly-in-milkyway/p/10385671.html