题解:AT_abc441_g [ABC441G] Takoyaki and Flip

题意

给你一些初始时正面朝上的盘子,对它进行 \(q\) 次以下操作:

  1. 将区间 \((l, r)\) 内所有正面朝上的盘子上放 \(x\) 个物品。

  2. 将区间 \((l, r)\) 内所有盘子翻转,并清空上面的物品。

  3. 求区间 \((l, r)\) 内所有盘子中最多的物品数量。

思路

显然,在最后一次翻转操作之前的所有区间加操作无用的,这里有点类似线段树的区间覆盖问题,考虑如何用线段树维护以及如何打标记。

考虑标记的合并,设进行了 \(a\) 次操作一, \(b\) 次操作二的标记为 \((a,b)\),若另一个标记 \((c,d)\) 与之合并。当 \(c=0\) 时,说明没有二操作去覆盖前面的一操作,则标记变为 \((a,b + d)\)。否则后面的二操作将其覆盖,标记变为 \((a+c,d)\)

考虑到只维护最大值是不可行的,因为对全反的盘子中放东西是不能对最大值造成影响的,所以考虑对记录正反盘子的个数,显然是好维护的。加标记时分讨一下即可,可以参考一下代码,这里不再赘述。

代码(轻微压行)

struct tag{
    int a, b;
    tag(int owo = 0, int qwq = 0){a = owo, b = qwq;}
}t[N << 2];
tag operator + (const tag&a, const tag&b){return ((b.a == 0) ? tag(a.a, a.b + b.b) : tag(a.a + b.a, b.b));}
struct tr{ int x, y, z;} s[N << 2];
#define ls id << 1
#define rs id << 1 | 1 
#define mid ((l + r) >> 1)
inline void add(tr &p, tag q){
    if(q.a % 2 == 0 && p.y == 0) p = {0, p.y, p.z};
    else if(q.a == 0 && p.y != 0) p = {p.x + q.b, p.y, p.z};
    else if(q.a > 0 && q.a % 2 == 0 && p.y != 0) p = {q.b, p.y, p.z};
    else if(q.a % 2 == 1 && p.z == 0) p = {0, p.z, p.y};
    else if(q.a % 2 == 1 && p.z != 0) p = {q.b, p.z, p.y};
}
inline void pushdown(int id){
    if(t[id].a || t[id].b){
        t[ls] = t[ls] + t[id], add(s[ls], t[id]);
        t[rs] = t[rs] + t[id], add(s[rs], t[id]);
        t[id] = {0, 0};
    }
}
inline void pushup(int id){s[id] = {max(s[ls].x, s[rs].x), s[ls].y + s[rs].y, s[ls].z + s[rs].z};}
inline void build(int id = 1, int l = 1, int r = n){
    if(l == r) return s[id] = {0, 1, 0}, void();
    build(ls, l, mid), build(rs, mid + 1, r);
    pushup(id);
}
inline void upd(int L, int R, tag v, int id = 1, int l = 1, int r = n){
    if(L <= l && r <= R){ t[id] = t[id] + v, add(s[id], v); return;}
    pushdown(id); 
    if(L <= mid) upd(L, R, v, ls, l, mid);
    if(R > mid) upd(L, R, v, rs, mid + 1, r);
    pushup(id);
}
inline int query(int L, int R, int id = 1, int l = 1, int r = n){
    if(L <= l && r <= R) return s[id].x;
    pushdown(id); int res = 0;
    if(L <= mid) res = max(res, query(L, R, ls, l, mid));
    if(R > mid) res = max(res, query(L, R, rs, mid + 1, r));
    return res;
}
signed main(){
    cin >> n >> q; build();
    for(int i = 1, op, l, r, x; i <= q; ++i){
        cin >> op;
        if(op == 1) cin >> l >> r >> x, upd(l, r, tag(0, x));
        else if(op == 2) cin >> l >> r, upd(l, r, tag(1, 0));
        else cin >> l >> r, cout << query(l, r) << '\n';
    }
    return 0;
}

posted @ 2026-02-02 17:13  Super_lollipop  阅读(1)  评论(0)    收藏  举报