強基計劃 題解

IANYEYZ發表於2024-07-25

強化基礎演算法,提升個人水平。

#65. 跳樹

考慮建線段樹,對每個節點維護 rt, l, num 分別代表最高跳到哪層,跳到最高後最低到哪層,以及往下跳的路徑(左兒子右兒子)。

然後合併時注意細節。

程式碼:

#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
using namespace std;
struct d {
    int rt, l, num;
    d(int rt = 0, int l = 0, int num = 0):rt(rt), l(l), num(num) {}
    d operator+(d o) {
        if (!rt && !l) return o;
        if (!o.rt && !o.l) return *this;
        if (l > o.rt) {
            d ans;
            ans.rt = rt;
            ans.l = l - o.rt + o.l;
            ans.num = ((num >> o.rt) << o.l) + o.num;
            return ans;
        } else {
            d ans;
            ans.rt = rt + o.rt - l;
            ans.l = o.l;
            ans.num = o.num;
            return ans;
        }
    }
    d operator =(d o) {
        rt = o.rt;
        l = o.l;
        num = o.num;
        return *this;
    }
}dat[2000010];
int opt[2000010], n, m, q, type, s, l, r, x, y;
d create(int opt) {
    if (opt == 1) return d(0, 1, 0);
    if (opt == 2) return d(0, 1, 1);
    if (opt == 3) return d(1, 0, 0);
}
void build(int p, int l, int r) {
    // cerr << p << " " << l << " " << r << "\n";
    if (l == r) {
        // cerr << p << "\n";
        dat[p] = create(opt[l]);
        // cerr << p << "\n";
    } else {
        int mid = (l + r) / 2;
        build(2 * p, l, mid);
        build(2 * p + 1, mid + 1, r);
        dat[p] = dat[2 * p] + dat[2 * p + 1];
    }
}
void modify(int p, int l, int r, int k) {
    if (l == r) {
        dat[p] = create(opt[l]);
    } else {
        int mid = (l + r) / 2;
        if (k > mid) modify(2 * p + 1, mid + 1, r, k);
        else         modify(2 * p, l, mid, k);
        dat[p] = dat[2 * p] + dat[2 * p + 1];
    }
}
d query(int p, int cl, int cr, int l, int r) {
    // cerr << p << " " << cl << " " << cr << " " << l << " " << r << "\n";
    if (l >= cl && r <= cr) {
        return dat[p];
    } else if (l > cr || r < cl) {
        return d();
    } else {
        int mid = (l + r) / 2;
        return query(2 * p, cl, cr, l, mid) + query(2 * p + 1, cl, cr, mid + 1, r);
    }
}
signed main() {
    // cerr << "here" << "\n";
    cin >> n >> m >> q;
    // cerr << "here" << "\n";
    rep (i, 1, m) {
        cin >> opt[i];
    }
    // cerr << "here" << "\n";
    build(1, 1, m);
    // cerr << "here" << "\n";
    rep (i, 1, q) {
        // cerr << i << "\n";
        cin >> type;
        if (type == 1) {
            cin >> s >> l >> r;
            d k = query(1, l, r, 1, m);
            cout << (max(1ll, s >> k.rt) << k.l) + k.num << "\n";
        } else {
            cin >> x >> y;
            opt[x] = y;
            modify(1, 1, m, x);
        }
    }
}

#66. [NOI Online #1 提高組] 氣泡排序

考慮記錄對於一個數,前面比它大的數有幾個。
然後一輪氣泡排序中,設對於某一個數,前面比它大的數的個數為 \(0\) 的數有 \(x\) 個,那麼這一輪會消掉 \(n - x\) 個逆序對。
隨後離散化後樹狀陣列即可。
程式碼:

#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
using namespace std;
int p[200010], v[200010], n, m, opt, c, sum;
struct BIT {
    int tr[200010];
    BIT() {}
    int lowbit(int i) { return i & -i; }
    void add(int x, int d) {
        x++;
        while (x) {
            tr[x] += d;
            x -= lowbit(x);
        }
    }
    int query(int x) {
        x++;
        int res = 0;
        while (x <= n) {
            res += tr[x];
            x += lowbit(x);
        }
        return res;
    }
    int queryPoint(int x) {
        return query(x) - query(x - 1);
    }
}tr1, tr2, tr3;
signed main() {
    int cnt = 0;
    cin >> n >> m;
    rep (i, 1, n) {
        cin >> p[i];
        sum += p[i];
        int x = tr3.query(p[i]);
        v[i] = x;
        tr2.add(x, v[i]);
        tr1.add(x, 1);
        tr3.add(p[i], 1);
    }
    rep (i, 1, m) {
        // cerr << i << "\n";
        // rep (j, 1, n) {
        //     cerr << v[j] << " ";
        // }
        // cerr << "\n";
        cin >> opt >> c;
        if (opt == 1) {
            tr2.add(v[c], -v[c]);
            tr2.add(v[c + 1], -v[c + 1]);
            tr1.add(v[c], -1);
            tr1.add(v[c + 1], -1);
            swap(v[c], v[c + 1]);
            if (p[c] < p[c + 1]) {
                v[c + 1]++;
            } else {
                v[c]--;
            }
            swap(p[c], p[c + 1]);
            tr2.add(v[c], v[c]);
            tr2.add(v[c + 1], v[c + 1]);
            tr1.add(v[c], 1);
            tr1.add(v[c + 1], 1);
        } else {
            int k = c;
            // k++;
            if (k >= n - 1) {
                cout << 0 << endl;
            } else {
                cout << tr2.query(k) - tr1.query(k) * k << endl;
            }
        }
    }
}

相關文章