洛谷 P2572 [SCOI2010]序列操作
阿新 • • 發佈:2020-09-21
瞎扯
好久沒寫線段樹了,找了一道線段樹題
然後……
寫了半個上午,調了半個上午+下午的半個小時……
沒 誰 了
思路
這道題難就難在標記的下放,如果標記下放正確了,A這道題就不是問題了。(然而我不想講下放= =)
如果沒有 \(4\) 操作和 \(2\) 操作,需要維護的東西就很少了,只需要維護區間內 \(1\) 的個數。但是因為有 \(4\) 操作和 \(2\) 操作,所以我們還要記錄幾個資訊:左端最長的 \(0\)、左端最長的 \(1\)、右端最長的 \(0\)、右端最長的 \(1\)、區間最長的連續的 \(0\)、區間最長的連續的 \(1\)(這裡說的哪個端是從區間端點開始的),這樣才能實現 \(2\)
下面看一下兩區間合併時,資訊如何合併:
- 左端最長連續的 \(0\) = 左區間左端最長連續的 \(0\) + {右區間左端最長連續的 \(0\)(如果左區間最長連續的 \(0\) 的個數等於左區間長度)}
- 左端最長連續的 \(1\) = 左區間左端最長連續的 \(1\) + {右區間左端最長連續的 \(1\)(如果左區間最長連續的 \(1\) 的個數等於左區間長度)}
- 右端最長連續的 \(0\) = 右區間右端最長連續的 \(0\) + {左區間右端最長連續的 \(0\)(如果右區間最長連續的 \(0\) 的個數等於右區間長度)}
- 右端最長連續的 \(1\) = 右區間右端最長連續的 \(1\)
- 區間內 \(1\) 的個數 = 左區間內 \(1\) 的個數 + 右區間內 \(1\) 的個數
- 區間最長連續的 \(1\) = \(\max(\)左區間最長連續 \(1\),右區間最長連續 \(1\), 左區間右端最長連續 \(1\) + 右區間左端最長連續 \(1\) \()\)
- 區間最長連續的 \(0\) = \(\max(\)左區間最長連續 \(0\),右區間最長連續 \(0\), 左區間右端最長連續 \(0\) + 右區間左端最長連續 \(0\) \()\)
然後要注意的就是標記的下傳了,這裡我們採用兩個標記,一個賦值標記,一個取反標記,顯然賦值標記的優先順序是大於取反標記的(其實我不知道為啥,就憑感覺覺得這樣是對的,評論區大佬可否解答?),所以我們先處理賦值標記,在處理賦值標記後,注意取反標記的貢獻應該取消,在處理取反標記時,賦值標記也要取反……詳細的實現可以看程式碼了……
程式碼
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, a[A];
struct node {
int sum1, l1, r1, max1;
void clear() { sum1 = 0, l1 = 0, r1 = 0, max1 = 0; }
};
struct tree {
int l, r, sum0, sum1, l0, l1, r0, r1, max1, max0, lazy1, lazy2;
} t[A << 2];
inline void pushup(int rt) {
t[rt].sum0 = t[lson].sum0 + t[rson].sum0;
t[rt].sum1 = t[lson].sum1 + t[rson].sum1;
t[rt].max0 = max(max(t[lson].max0, t[rson].max0), t[lson].r0 + t[rson].l0);
t[rt].max1 = max(max(t[lson].max1, t[rson].max1), t[lson].r1 + t[rson].l1);
t[rt].l0 = t[lson].l0 + t[rson].l0 * (t[lson].l0 == (t[lson].r - t[lson].l + 1));
t[rt].l1 = t[lson].l1 + t[rson].l1 * (t[lson].l1 == (t[lson].r - t[lson].l + 1));
t[rt].r0 = t[rson].r0 + t[lson].r0 * (t[rson].r0 == (t[rson].r - t[rson].l + 1));
t[rt].r1 = t[rson].r1 + t[lson].r1 * (t[rson].r1 == (t[rson].r - t[rson].l + 1));
return;
}
inline void tag(int rt) {
swap(t[rt].max0, t[rt].max1);
swap(t[rt].sum0, t[rt].sum1);
swap(t[rt].r0, t[rt].r1);
swap(t[rt].l0, t[rt].l1);
t[rt].lazy2 ^= 1, t[rt].lazy1 ^= 1;
return;
}
inline void change1(int rt) {
int len = t[rt].r - t[rt].l + 1;
t[rt].sum0 = 0, t[rt].max0 = 0, t[rt].l0 = 0, t[rt].r0 = 0;
t[rt].sum1 = len, t[rt].max1 = len, t[rt].l1 = len, t[rt].r1 = len;
t[rt].lazy1 = 1, t[rt].lazy2 = 0;
return;
}
inline void change0(int rt) {
int len = t[rt].r - t[rt].l + 1;
t[rt].sum1 = 0, t[rt].max1 = 0, t[rt].l1 = 0, t[rt].r1 = 0;
t[rt].sum0 = len, t[rt].max0 = len, t[rt].l0 = len, t[rt].r0 = len;
t[rt].lazy1 = 0, t[rt].lazy2 = 0;
return;
}
inline void pushdown(int rt) {
if (t[rt].lazy1 == 1) {
change1(lson), change1(rson);
t[rt].lazy1 = -1, t[rt].lazy2 = 0;
}
else if (t[rt].lazy1 == 0) {
change0(lson), change0(rson);
t[rt].lazy1 = -1, t[rt].lazy2 = 0;
}
if (t[rt].lazy2 == 1) {
tag(lson), tag(rson);
t[rt].lazy2 = 0, t[rt].lazy1 = -1;
}
}
void build(int rt, int l, int r) {
t[rt].l = l, t[rt].r = r, t[rt].lazy1 = -1;
if (l == r) {
int now = a[l];
if (now == 1) {
t[rt].l1 = 1, t[rt].r1 = 1;
t[rt].sum1 = 1, t[rt].max1 = 1;
}
else {
t[rt].l0 = 1, t[rt].r0 = 1;
t[rt].sum0 = 1, t[rt].max0 = 1;
}
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(rt);
}
void update(int rt, int l, int r, int who) {
if (l <= t[rt].l && t[rt].r <= r) {
pushdown(rt);
if (who) {
change1(rt);
} else {
change0(rt);
}
return;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if (l <= mid) {
update(lson, l, r, who);
}
if (r > mid) {
update(rson, l, r, who);
}
pushup(rt);
}
void Negate(int rt, int l, int r) {
if (l <= t[rt].l && t[rt].r <= r) {
pushdown(rt);
tag(rt);
return;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if (l <= mid) Negate(lson, l, r);
if (r > mid) Negate(rson, l, r);
pushup(rt);
}
node conseq(int rt, int l, int r) {
node now, ls, rs;
now.clear(), ls.clear(), rs.clear();
if (l <= t[rt].l && t[rt].r <= r) {
now.l1 = t[rt].l1, now.max1 = t[rt].max1, now.r1 = t[rt].r1, now.sum1 = t[rt].sum1;
return now;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if (l <= mid) ls = conseq(lson, l, r);
if (r > mid) rs = conseq(rson, l, r);
now.sum1 = ls.sum1 + rs.sum1;
now.max1 = max(max(ls.max1, rs.max1), ls.r1 + rs.l1);
now.l1 = ls.l1 + rs.l1 * (ls.l1 == (t[lson].r - t[lson].l + 1));
now.r1 = rs.r1 + ls.r1 * (rs.r1 == (t[rson].r - t[rson].l + 1));
return now;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read();
build(1, 1, n);
while (m--) {
int opt = read(), x = read() + 1, y = read() + 1;
if (opt == 1 || opt == 0) update(1, x, y, opt);
else if (opt == 2) Negate(1, x, y);
else if (opt == 3) cout << conseq(1, x, y).sum1 << '\n';
else if (opt == 4) cout << conseq(1, x, y).max1 << '\n';
}
return 0;
}