CF292E Copying Data 题解

你谷传送门

原题传送门

分析

一眼可以看出,这题实际上是让你维护区间覆盖、单点查询操作。于是考虑线段树。

进一步观察可以发现,一次覆盖操作实际上是把 \(a_x\) 及其后的 \(k-1\) 个元素赋给 \(b_y\) 及其后的 \(k-1\) 个元素。我们画个图来理解一下:

样例,但是不完全样例

也就是 \(b\) 数组里的每一个 \(b_y\) 在一次操作后都会变成 \(a\) 数组里的一个 \(a_{y+\Delta}\)。这个 \(\Delta\) 其实就是这次操作的 \(x - y\)。可以发现 \(\Delta\) 其实是 \(b\) 里某段区间的一个属性,代表这个区间里的每个 \(b_x\) 都即将被改成 \(a_{x+\Delta}\)。所以这玩意显然是可以用线段树维护的。把 \(\Delta\) 作为懒标记,每次将 \(\Delta\) 下传。查询时查到叶子就直接返回 \(a\) 里的对应值。

由于 \(x\)\(y\) 可以相等,所以 \(\Delta\) 可以是 \(0\)。所以我们就不能用 \(0\) 标记区间没有被覆盖过,而要用无穷大来标记。

代码

#include <iostream>
using namespace std;
const int N = 131072;
const int inf = 2147483647;
int a[N << 2], b[N << 2];
int tag[N << 2];
void Build(int o, int l, int r) {
    tag[o] = -inf; // 初始化懒标记:这里没有被覆盖过
    if (l == r) 
        return;
    int mid = (l + r) >> 1;
    Build(o << 1, l, mid);
    Build(o << 1 | 1, mid + 1, r);
}
void pushdown(int o) {
    if (tag[o] == -inf) 
        return;
    int t = tag[o];
    tag[o] = -inf;
    tag[o << 1] = tag[o << 1 | 1] = t; // 左右儿子都要移 △ 位
}
void Change(int o, int l, int r, int L, int R, int d) {
    if (L <= l && r <= R) {
        tag[o] = d; // 赋为 △
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (L <= mid) 
        Change(o << 1, l, mid, L, R, d);
    if (R > mid) 
        Change(o << 1 | 1, mid + 1, r, L, R, d);
}
int Query(int o, int l, int r, int x) {
    if (l == r) 
        return (tag[o] == -inf ? b[x] : a[x + tag[o]]);
        // 如果没有被覆盖过,则返回原本值。如果被覆盖过,返回 a 里的对应值。
    pushdown(o);
    int mid = (l + r) >> 1;
    if (x <= mid) 
        return Query(o << 1, l, mid, x);
    else 
        return Query(o << 1 | 1, mid + 1, r, x);
}
int main() {
    Build(1, 1, N);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) scanf("%d", a + i);
    for (int i = 1; i <= n; i++) scanf("%d", b + i);
    while (m--) {
        int op, x, y, k;
        cin >> op;
        if (op == 1) {
            cin >> x >> y >> k;
            Change(1, 1, N, y, y + k - 1, x - y); // △ = x - y
        } else {
            cin >> x;
            cout << Query(1, 1, N, x) << "\n";
        }
    }
    return 0;
}

完结撒花~~~

posted @ 2023-05-12 22:17  forgotmyhandle  阅读(28)  评论(0)    收藏  举报