[Ynoi2012] NOIP2015 充滿了希望

ccxswl發表於2024-10-04

[Ynoi2012] NOIP2015 充滿了希望

題意

給一個長為 \(n\) 的序列,有 \(m\) 個操作,操作編號從 \(1\)\(m\),每個操作為:

1 x y:將序列位置為 \(x,y\) 的兩個元素交換。

2 l r x:將序列區間 \([l,r]\) 內所有元素修改為 \(x\)

3 x:查詢序列 \(x\) 位置的值。

現在有 \(q\) 次查詢,每次查詢給出一個操作的區間 \([l,r]\)

先將序列中的元素全部置為 \(0\),之後依次進行從 \(l\)\(r\) 的所有操作,求出所有這些操作中所有 \(3\) 操作的答案的和。

查詢之間獨立。

思路

套路一樣

用線段樹維護一個元素被哪一次的操作染色(操作的編號)。對詢問離線,按 \(r\) 排序,對其做掃描線。

由於詢問已經拍好序,考慮第 \(i\) 個詢問的時候已經操作完了 \(1\sim r_i\) 的操作。我們只想要 \(l_i\sim r_i\) 之間操作貢獻的答案,如何消除 \(1\sim l_i-1\) 的操作對答案的影響呢?

把每次的操作三查詢出的答案以操作的時間為下標放到樹狀陣列裡,表示它會對之後的查詢造成影響,那我們詢問的時候就可以直接用樹狀陣列區間查詢統計答案。具體的,就是 bit.ask(r) - bit.ask(l-1)

大致思路就是這樣,具體的操作也比較好實現。操作一是兩個單點修改,操作二是區間覆蓋。

程式碼

#include <bits/stdc++.h>

using namespace std;

using ubt = long long;

inline int read() {
    int s = 0, w = 1;
    char c = getchar();
    while (!isdigit(c)) {
        if (c == '-')
            w = -w;
        c = getchar();
    }
    while (isdigit(c)) {
        s = s * 10 + c - 48;
        c = getchar();
    }
    return s * w;
}

const int maxN = 1e6 + 7;

int n, m, Q;

struct BIT {
    ubt t[maxN];
    void add(int x, int v) {
        for (; x && x <= m; x += x & -x)
            t[x] += v;
    }
    ubt ask(int x) {
        ubt res = 0;
        for (; x > 0; x -= x & -x)
            res += t[x];
        return res;
    }
    ubt query(int x, int y) {
        return ask(y) - ask(x - 1);
    }
} bit;

struct Tree {
    int l, r;
    int v, lz;
} t[maxN << 2];
#define ls (p << 1)
#define rs (p << 1 | 1)
void make(int p, int lz) {
    t[p].lz = lz;
    t[p].v = lz;
}
void down(int p) {
    if (!t[p].lz) return;
    make(ls, t[p].lz);
    make(rs, t[p].lz);
    t[p].lz = 0;
}
void build(int L, int R, int p) {
    t[p].l = L, t[p].r = R;
    if (L == R) return;
    int mid = (L + R) >> 1;
    build(L, mid, ls), build(mid + 1, R, rs);
}
void change(int L, int R, int p, int v) {
    if (L <= t[p].l && t[p].r <= R)
        make(p, v);
    else {
        down(p);
        int mid = (t[p].l + t[p].r) >> 1;
        if (L <= mid)
            change(L, R, ls, v);
        if (R > mid)
            change(L, R, rs, v);
    }
}
int ask(int K, int p) {
    if (t[p].l == t[p].r)
        return t[p].v;
    down(p);
    int mid = (t[p].l + t[p].r) >> 1;
    return K <= mid ? ask(K, ls) : ask(K, rs);
}
void Swap(int x, int y) {
    int resx = ask(x, 1);
    int resy = ask(y, 1);
    change(x, x, 1, resy);
    change(y, y, 1, resx);
}

struct modi {
    int op, x, y, k;
    int id;
} mo[maxN];

void modify(modi G) {
    if (G.op == 1)
        Swap(G.x, G.y);
    if (G.op == 2)
        change(G.x, G.y, 1, G.id);
    if (G.op == 3) {
        int t = ask(G.x, 1);
        bit.add(t, mo[t].k);
    }
}

struct ques {
    int l, r, id;
    friend bool operator < (ques A, ques B) {
        return A.r < B.r;
    }
} q[maxN];
ubt ans[maxN];

int main() {
    n = read(), m = read(), Q = read();
    build(1, n, 1);
    
    mo[0].k = 0;
    for (int i = 1; i <= m; i++) {
        mo[i].id = i;
        mo[i].op = read();
        mo[i].x = read();
        if (mo[i].op != 3) {
            mo[i].y = read();
            if (mo[i].op == 2)
                mo[i].k = read();
        }
    }

    for (int i = 1; i <= Q; i++)
        q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + Q + 1);

    int now = 1;
    for (int nw = 1; nw <= Q; nw++) {
        int l = q[nw].l, r = q[nw].r;
        while (now <= m && now <= r)
            modify(mo[now++]);
        ans[q[nw].id] = bit.query(l, r);
    }

    for (int i = 1; i <= Q; i++)
        cout << ans[i] << '\n';
}

相關文章