整体二分板子

P3834 可持久化线段树 2

静态区间第 \(k\) 小。

存个不带修整体二分板子。

离散化,拿树状数组维护一下元素出现次数。

假设当前区间内所有答案都是 \(mid\)

实时更新,这样就可以计算 \(\le mid\) 的数,也就是排名啦。

#include <bits/stdc++.h>
#define lowbit(x) (x & -x)
using namespace std;

const int N = 5e5 + 10, inf = 1e9;
int n, m, tot, a[N], b[N], t[N], res[N];
unordered_map <int, int> Map;

inline void upd(int pos, int val) {
    for (; pos <= n; pos += lowbit(pos)) t[pos] += val;
    return ;
}

inline int query(int pos, int res = 0) {
    for (; pos; pos -= lowbit(pos)) res += t[pos];
    return res;
}

struct Query { int l, r, k, id, typ; } qry[N], qy[N], _qy[N];
inline void solve(int l, int r, int ql, int qr) {
    if (ql > qr) return ;
    if (l == r) {
        for (int i = ql; i <= qr; ++i)
            if (qry[i].typ == 2) res[qry[i].id] = l;
        return ;
    }
    int mid = (l + r) >> 1, cnt = 0, _cnt = 0;
    for (int i = ql; i <= qr; ++i) {
        if (qry[i].typ & 1) {
            if (qry[i].l <= mid)
                upd(qry[i].id, 1), qy[++cnt] = qry[i];
            else _qy[++_cnt] = qry[i];
        } else {
            int k = query(qry[i].r) - query(qry[i].l - 1);
            if (qry[i].k <= k) qy[++cnt] = qry[i];
            else qry[i].k -= k, _qy[++_cnt] = qry[i];
        }
    }
    for (int i = 1; i <= cnt; ++i)
        if (qy[i].typ & 1) upd(qy[i].id, -1);
    for (int i = 1; i <= cnt; ++i) qry[ql + i - 1] = qy[i];
    for (int i = 1; i <= _cnt; ++i) qry[ql + cnt + i - 1] = _qy[i];
    solve(l, mid, ql, ql + cnt - 1);
    solve(mid + 1, r, ql + cnt, qr); return ;
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
    cin >> n >> m; for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i];
    sort(b + 1, b + 1 + n); int len = unique(b + 1, b + 1 + n) - b - 1;
    for (int i = 1; i <= n; ++i) Map[a[i]] = lower_bound(b + 1, b + 1 + len, a[i]) - b;
    for (int i = 1; i <= n; ++i) qry[++tot] = {Map[a[i]], -1, -1, i, 1};
    for (int i = 1, l, r, k; i <= m; ++i)
        cin >> l >> r >> k, qry[++tot] = {l, r, k, i, 2};
    solve(1, len, 1, tot);
    for (int i = 1; i <= m; ++i) cout << b[res[i]] << endl;
    return 0;
}

P1527 矩阵乘法

静态子矩形内第 \(k\) 小。

相同的做法,二维的树状数组。没了。

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define lowbit(x) ((x) & -(x))
using namespace std;

template <typename T> inline void read(T &x) {
    x = 0; char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
}

template <typename T, typename ...Args>
inline void read(T &x, Args &...args) { read(x), read(args...); }

const int N = 1e3 + 10, M = 1e6 + 10;
int n, q, tot, b[M], res[M], a[N][N], t[N][N];
__gnu_pbds::gp_hash_table <int, int> Map;

inline void upd(int x, int y, int val) {
    for (int i = x; i <= n; i += lowbit(i))
        for (int j = y; j <= n; j += lowbit(j)) t[i][j] += val;
    return ;
}

inline int query(int x, int y, int res = 0) {
    for (int i = x; i; i -= lowbit(i))
        for (int j = y; j; j -= lowbit(j)) res += t[i][j];
    return res;
}

struct Query { int l, r, _l, _r, k, x, y, typ; } qry[M], qy[M], _qy[M];
inline void solve(int l, int r, int ql, int qr) {
    if (ql > qr) return ;
    if (l == r) {
        for (int i = ql; i <= qr; ++i)
            if (qry[i].typ == 2) res[qry[i].x] = l;
        return ;
    }
    int cnt = 0, _cnt = 0, mid = (l + r) >> 1;
    for (int i = ql; i <= qr; ++i) {
        if (qry[i].typ & 1) {
            if (qry[i].l <= mid) upd(qry[i].x, qry[i].y, 1), qy[++cnt] = qry[i];
            else _qy[++_cnt] = qry[i];
        } else {
            int k = query(qry[i]._l, qry[i]._r);
            k -= query(qry[i].l - 1, qry[i]._r) + query(qry[i]._l, qry[i].r - 1);
            k += query(qry[i].l - 1, qry[i].r - 1);
            if (qry[i].k <= k) qy[++cnt] = qry[i];
            else qry[i].k -= k, _qy[++_cnt] = qry[i];
        }
    }
    for (int i = 1; i <= cnt; ++i)
        if (qy[i].typ & 1) upd(qy[i].x, qy[i].y, -1);
    for (int i = 1; i <= cnt; ++i) qry[ql + i - 1] = qy[i];
    for (int i = 1; i <= _cnt; ++i) qry[ql + cnt + i - 1] = _qy[i];
    solve(l, mid, ql, ql + cnt - 1);
    solve(mid + 1, r, ql + cnt, qr); return ;
}

int main() {
    read(n, q); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
        read(a[i][j]), b[++tot] = a[i][j];
    sort(b + 1, b + 1 + tot); int len = unique(b + 1, b + 1 + tot) - b - 1;
    for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
        Map[a[i][j]] = lower_bound(b + 1, b + 1 + len, a[i][j]) - b; tot = 0;
    for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
        qry[++tot] = {Map[a[i][j]], -1, -1, -1, -1, i, j, 1};
    for (int i = 1, l, r, _l, _r, k; i <= q; ++i)
        read(l, r, _l, _r, k), qry[++tot] = {l, r, _l, _r, k, i, 0, 2};
    solve(1, len, 1, tot); for (int i = 1; i <= q; ++i) printf("%d\n", b[res[i]]);
    return 0;
}

P2617 Dynamic Rankings

想当年我是拿分块写的这题。

带修整体二分板子题。

把修改操作拆成删除上一次该位置上的元素,和在这个位置上添加一个元素。

对于每个操作记一个标记 \(tag\) 就行,撤销操作就加上 \(-tag\)

就酱。双 \(\log\) 无所畏惧。

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define lowbit(x) (x & -x)
using namespace std;

template <typename T> inline void read(T &x) {
    x = 0; char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
} template <typename T, typename ...Args>
inline void read(T &x, Args &...args) { read(x), read(args...); }
inline void readch(char &ch) {
    ch = getchar(); while (ch > 'Z' || ch < 'A') ch = getchar(); return ;
} template <typename T> inline void write(T x) {
    if (x > 9) write(x / 10); putchar(x % 10 ^ 48); return ;
}

const int N = 5e5 + 10;
int n, m, g, tot, a[N], b[N], t[N], lst[N], res[N];
__gnu_pbds::gp_hash_table <int, int> Map;
struct Query { int l, r, k, id, typ, val; } qry[N], qy[N], _qy[N];
struct haha { char op; int l, r, k; } h[N];

inline void upd(int pos, int val) {
    for (; pos <= n; pos += lowbit(pos)) t[pos] += val;
    return ;
}

inline int query(int pos, int res = 0) {
    for (; pos; pos -= lowbit(pos)) res += t[pos];
    return res;
}

inline void solve(int l, int r, int ql, int qr) {
    if (ql > qr) return ;
    if (l == r) {
        for (int i = ql; i <= qr; ++i)
            if (qry[i].typ == 2) res[qry[i].id] = l;
        return ;
    }
    int mid = (l + r) >> 1, cnt = 0, _cnt = 0;
    for (int i = ql; i <= qr; ++i) {
        if (qry[i].typ & 1) {
            if (qry[i].l <= mid) upd(qry[i].id, qry[i].val), qy[++cnt] = qry[i];
            else _qy[++_cnt] = qry[i];
        } else {
            int k = query(qry[i].r) - query(qry[i].l - 1);
            if (qry[i].k <= k) qy[++cnt] = qry[i];
            else qry[i].k -= k, _qy[++_cnt] = qry[i];
        }
    }
    for (int i = 1; i <= cnt; ++i) if (qy[i].typ & 1) upd(qy[i].id, -qy[i].val);
    for (int i = 1; i <= cnt; ++i) qry[ql + i - 1] = qy[i];
    for (int i = 1; i <= _cnt; ++i) qry[ql + cnt + i - 1] = _qy[i];
    solve(l, mid, ql, ql + cnt - 1);
    solve(mid + 1, r, ql + cnt, qr); return ;
}

int main() {
    read(n, m); for (int i = 1; i <= n; ++i) read(a[i]), b[++g] = a[i];
    for (int i = 1; i <= m; ++i) {
        readch(h[i].op), read(h[i].l, h[i].r);
        if (h[i].op == 'Q') read(h[i].k); else b[++g] = h[i].r;
    }
    sort(b + 1, b + 1 + g); int len = unique(b + 1, b + 1 + g) - b - 1;
    for (int i = 1; i <= n; ++i) Map[a[i]] = lower_bound(b + 1, b + 1 + len, a[i]) - b;
    for (int i = 1; i <= m; ++i)
        if (h[i].op == 'C') Map[h[i].r] = lower_bound(b + 1, b + 1 + len, h[i].r) - b;
    for (int i = 1; i <= n; ++i) qry[++tot] = {lst[i] = Map[a[i]], -1, -1, i, 1, 1};
    for (int i = 1; i <= m; ++i) {
        if (h[i].op == 'Q') qry[++tot] = {h[i].l, h[i].r, h[i].k, i, 2, 0};
        else {
            qry[++tot] = {lst[h[i].l], -1, -1, h[i].l, 1, -1};
            qry[++tot] = {lst[h[i].l] = Map[h[i].r], -1, -1, h[i].l, 1, 1};
        }
    }
    solve(1, len, 1, tot); for (int i = 1; i <= m; ++i)
        if (res[i]) write(b[res[i]]), puts("");
    return 0;
}
posted @ 2023-03-10 17:13  MistZero  阅读(23)  评论(0编辑  收藏  举报