競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 322F問題

\(\def \set #1#2{\{ #1 \ \vert \ #2 \}}\) \(\def \ra {\rightarrow}\)

ABC322F

解法

(交わらない)隣の二つの区間 \(I,J\) を結合したときを考える. 基本的には,\(I,J\) それぞれの 1 の連続区間の最大が \(I \cup J\) における最大となる.
しかし,結合したときに \(I\) の右端から伸びる連続する 1の区間と, \(J\) の左端から伸びる連続する 1の区間が結合するため, これが最大になる場合がある. また,区間全体が 1のときも注意が必要.
クエリ 1 により,0と 1を反転させるので,同様に \(I\) の左(右)から伸びる連続 0の区間の長さも持っておく. これらの情報を区間毎にもっておけば,lazy segtree で計算が出来る.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

struct D{
  ll ma, l, r;
  D(){
    ma = 0, l = 0, r = 0; // [*]
  }
};

struct S{
  ll len;
  D d[2];
  S(){
    // len = 0 も書いた方が安全な気はする.
    // 書いてなくても ACしたけど.
  }
  S(bool c){
    len = 1;
    d[c].l = 1;
    d[c].r = 1;
    d[c].ma = 1;
    // rem: c^1 の初期化も忘れない
    // [*] において,Dのコンストラクタで初期化しているなら,
    // 以下は書かなくても OK.
    // d[c^1].l = 0;
    // d[c^1].r = 0;
    // d[c^1].ma = 0;
  }

  void show(string name = ""){
    cout << name << endl;
    cout << "len : " << len << endl;
    rep(i,2){
      cout << "i : " << i << endl;
      cout << "d[i].ma : " << d[i].ma << endl;
      cout << "d[i].l : " << d[i].l << endl;
      cout << "d[i].r : " << d[i].r << endl;
    }
    cout << endl;
  }
};

S op(S a, S b){
  S c;
  c.len = a.len + b.len;
  rep(i,2) c.d[i].l = a.len != a.d[i].l ? a.d[i].l : (a.len + b.d[i].l);
  rep(i,2) c.d[i].r = b.len != b.d[i].r ? b.d[i].r : (a.d[i].r + b.len);
  rep(i,2) c.d[i].ma = max(a.d[i].ma, max(b.d[i].ma, a.d[i].r + b.d[i].l));
  return c;
}

S e(){
  S c;
  rep(i,2) c.d[i].ma = 0;
  rep(i,2) c.d[i].l = 0;
  rep(i,2) c.d[i].r = 0;
  c.len = 0;
  return c;
}

using F = bool;
S mapping(F f, S x){
  if(f) swap(x.d[0], x.d[1]);
  return x;
}

F composition(F f, F g){
  return f^g;
}

F id(){
  return false;
}

int main() {
  ll n,q;
  cin >> n >> q;
  string s; cin >> s;
  lazy_segtree<S,op,e,F,mapping,composition,id> t(n);
  rep(i,n){
    t.set(i, S(s[i]-'0'));
  }


  rep(qi,q){
    ll c; cin >> c;
    ll l,r; cin >> l >> r;
    --l;
    if(c == 1){
      t.apply(l,r,true);
    }else{
      cout << t.prod(l,r).d[1].ma << endl;
    }
  }


  return 0;
}