1. 程式人生 > 實用技巧 >洛谷 P2572 [SCOI2010]序列操作

洛谷 P2572 [SCOI2010]序列操作

瞎扯

好久沒寫線段樹了,找了一道線段樹題
然後……

寫了半個上午,調了半個上午+下午的半個小時……
沒 誰 了

思路

這道題難就難在標記的下放,如果標記下放正確了,A這道題就不是問題了。(然而我不想講下放= =)

如果沒有 \(4\) 操作和 \(2\) 操作,需要維護的東西就很少了,只需要維護區間內 \(1\) 的個數。但是因為有 \(4\) 操作和 \(2\) 操作,所以我們還要記錄幾個資訊:左端最長的 \(0\)、左端最長的 \(1\)、右端最長的 \(0\)、右端最長的 \(1\)、區間最長的連續的 \(0\)、區間最長的連續的 \(1\)(這裡說的哪個端是從區間端點開始的),這樣才能實現 \(2\)

操作和 \(4\) 操作。

下面看一下兩區間合併時,資訊如何合併:

  1. 左端最長連續的 \(0\) = 左區間左端最長連續的 \(0\) + {右區間左端最長連續的 \(0\)(如果左區間最長連續的 \(0\) 的個數等於左區間長度)}
  2. 左端最長連續的 \(1\) = 左區間左端最長連續的 \(1\) + {右區間左端最長連續的 \(1\)(如果左區間最長連續的 \(1\) 的個數等於左區間長度)}
  3. 右端最長連續的 \(0\) = 右區間右端最長連續的 \(0\) + {左區間右端最長連續的 \(0\)(如果右區間最長連續的 \(0\) 的個數等於右區間長度)}
  4. 右端最長連續的 \(1\) = 右區間右端最長連續的 \(1\)
    + {左區間右端最長連續的 \(1\)(如果右區間最長連續的 \(1\) 的個數等於右區間長度)}
  5. 區間內 \(1\) 的個數 = 左區間內 \(1\) 的個數 + 右區間內 \(1\) 的個數
  6. 區間最長連續的 \(1\) = \(\max(\)左區間最長連續 \(1\),右區間最長連續 \(1\), 左區間右端最長連續 \(1\) + 右區間左端最長連續 \(1\) \()\)
  7. 區間最長連續的 \(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;
}