题解:SP31938 QUERYIT - SLIS

经典线段树题。

\(01\) 序列的不下降子序列一定是 \(00\cdots 0011\cdots 11\) 的形式,由于需要区间取反操作,我们也必须把不上升子序列 \(11\cdots 1100\cdots 00\) 的信息维护上。

线段树维护 \(\operatorname{cnt0}(u),\operatorname{cnt1}(u),\operatorname{ans01}(u),\operatorname{ans10}(u)\) 依次表示节点 \(u\) 对应区间内 \(0\) 的个数、\(1\) 的个数、最长 \(00\cdots 0011\cdots 11\) 子序列长度、最长 \(11\cdots 1100\cdots 00\) 子序列长度。

设节点 \(u\) 的左右儿子分别为 \(\operatorname{lc}(u),\operatorname{rc}(u)\),则可以按照如下方式合并子节点信息:

\[\begin{aligned} \operatorname{cnt0}(u)&=\operatorname{cnt0}(\operatorname{lc}(u))+\operatorname{cnt0}(\operatorname{rc}(u))\\ \operatorname{cnt1}(u)&=\operatorname{cnt1}(\operatorname{lc}(u))+\operatorname{cnt1}(\operatorname{rc}(u))\\ \operatorname{ans01}(u)&=\max\{\operatorname{ans01}(\operatorname{lc}(u))+\operatorname{cnt1}(\operatorname{rc}(u)),\operatorname{cnt0}(\operatorname{lc}(u))+\operatorname{ans01}(\operatorname{rc}(u))\}\\ \operatorname{ans10}(u)&=\max\{\operatorname{ans10}(\operatorname{lc}(u))+\operatorname{cnt0}(\operatorname{rc}(u)),\operatorname{cnt1}(\operatorname{lc}(u))+\operatorname{ans10}(\operatorname{rc}(u))\}\\ \end{aligned} \]

维护区间反转标记,当节点对应区间整个被反转时,只需打标记并交换 \(\operatorname{cnt0}(u)\)\(\operatorname{cnt1}(u)\)\(\operatorname{ans01}(u)\)\(\operatorname{ans10}(u)\) 即可。

时间复杂度 \(O(n+m\log n)\)

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do {freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);} while(false)
#define endl '\n'
using namespace std;
typedef long long ll;

mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
    uniform_int_distribution<int> dist(L, R);
    return dist(rnd);
}

template<typename T> void chkmin(T& x, T y) {if(y < x) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}

template<int mod>
inline unsigned int down(unsigned int x) {
	return x >= mod ? x - mod : x;
}

template<int mod>
struct Modint {
	unsigned int x;
	Modint() = default;
	Modint(unsigned int x) : x(x) {}
	friend istream& operator>>(istream& in, Modint& a) {return in >> a.x;}
	friend ostream& operator<<(ostream& out, Modint a) {return out << a.x;}
	friend Modint operator+(Modint a, Modint b) {return down<mod>(a.x + b.x);}
	friend Modint operator-(Modint a, Modint b) {return down<mod>(a.x - b.x + mod);}
	friend Modint operator*(Modint a, Modint b) {return 1ULL * a.x * b.x % mod;}
	friend Modint operator/(Modint a, Modint b) {return a * ~b;}
	friend Modint operator^(Modint a, int b) {Modint ans = 1; for(; b; b >>= 1, a *= a) if(b & 1) ans *= a; return ans;}
	friend Modint operator~(Modint a) {return a ^ (mod - 2);}
	friend Modint operator-(Modint a) {return down<mod>(mod - a.x);}
	friend Modint& operator+=(Modint& a, Modint b) {return a = a + b;}
	friend Modint& operator-=(Modint& a, Modint b) {return a = a - b;}
	friend Modint& operator*=(Modint& a, Modint b) {return a = a * b;}
	friend Modint& operator/=(Modint& a, Modint b) {return a = a / b;}
	friend Modint& operator^=(Modint& a, int b) {return a = a ^ b;}
	friend Modint& operator++(Modint& a) {return a += 1;}
	friend Modint operator++(Modint& a, int) {Modint x = a; a += 1; return x;}
	friend Modint& operator--(Modint& a) {return a -= 1;}
	friend Modint operator--(Modint& a, int) {Modint x = a; a -= 1; return x;}
	friend bool operator==(Modint a, Modint b) {return a.x == b.x;}
	friend bool operator!=(Modint a, Modint b) {return !(a == b);}
};

const int N = 1e5 + 5;

int n, m, a[N];
string s;

struct Node {
    int cnt0, cnt1, ans01, ans10;
    Node(int cnt0 = 0, int cnt1 = 0, int ans01 = 0, int ans10 = 0): 
        cnt0(cnt0), cnt1(cnt1), ans01(ans01), ans10(ans10) {}
    friend Node operator+(Node a, Node b) {
        return Node(
            a.cnt0 + b.cnt0,
            a.cnt1 + b.cnt1, 
            max(a.ans01 + b.cnt1, a.cnt0 + b.ans01), 
            max(a.ans10 + b.cnt0, a.cnt1 + b.ans10)
        );
    }
    friend Node operator-(Node a) {
        return Node(a.cnt1, a.cnt0, a.ans10, a.ans01);
    }
};

struct SegTree {
    Node t[N << 2];
    int tag[N << 2];
    #define lc(u) (u << 1)
    #define rc(u) (u << 1 | 1)
    void build(int* a, int u, int l, int r) {
        if(l == r) {
            t[u] = Node(a[l] == 0, a[l] == 1, 1, 1);
            return;
        }
        int mid = (l + r) >> 1;
        build(a, lc(u), l, mid);
        build(a, rc(u), mid + 1, r);
        t[u] = t[lc(u)] + t[rc(u)];
    }
    void pushtag(int u) {
        tag[u] ^= 1;
        t[u] = -t[u];
    }
    void pushdown(int u) {
        if(!tag[u]) return;
        pushtag(lc(u));
        pushtag(rc(u));
        tag[u] = 0;
    }
    void modify(int u, int l, int r, int ql, int qr) {
        if(ql <= l && r <= qr) {
            pushtag(u);
            return;
        }
        pushdown(u);
        int mid = (l + r) >> 1;
        if(ql <= mid) modify(lc(u), l, mid, ql, qr);
        if(qr > mid) modify(rc(u), mid + 1, r, ql, qr);
        t[u] = t[lc(u)] + t[rc(u)];
    }
    #undef lc
    #undef rc
}sgt;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m >> s;
    rep(i, 1, n) a[i] = s[i - 1] - '0';
    sgt.build(a, 1, 1, n);
    while(m--) {
        int op;
        cin >> op;
        if(op == 0) {
            int l, r;
            cin >> l >> r;
            sgt.modify(1, 1, n, l, r);
        }
        else cout << sgt.t[1].ans01 << endl;
    }
    return 0;
}
posted @ 2025-07-22 23:43  rui_er  阅读(17)  评论(0)    收藏  举报