[Ynoi2012] NOIP2015 充满了希望

[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';
}
posted @ 2024-10-04 22:00  ccxswl  阅读(12)  评论(0编辑  收藏  举报