0w1

CFR 380 C. Sereja and Brackets ( Segment Tree, D&C, Bracket Sequence )

Problem - 380C - Codeforces

題意:
給一個括弧序列,和若干筆詢問。詢問給 L, R,問原序列的 [ L, R ] 區間裡最常的合法匹配序列 ( 可間斷 ) 多長 。

資料規模:
序列長度 ≤ 1e6
詢問數 ≤ 1e5

解法:
考慮基於分治的預處理。如果我們知道一個區間分別的最長合法匹配序列長度; 未使用的左括弧數量; 未使用的右括弧數量,便足以正確更新。詳見代碼。

時間 / 空間複雜度:
O( | S | lg | S | ) / O( | S | )

#include <bits/stdc++.h>
using namespace std;

const int MAXN = ( int ) 1e6 + 5;

struct segt{
  int maxlen[ MAXN << 3 ], unlb[ MAXN << 3 ], unrb[ MAXN << 3 ]; // unused left / right bracket
  void pull( int t ){
    int newb = min( unlb[ t << 1 ], unrb[ t << 1 | 1 ] );
    maxlen[ t ] = maxlen[ t << 1 ] + maxlen[ t << 1 | 1 ] + newb;
    unlb[ t ] = unlb[ t << 1 ] + unlb[ t << 1 | 1 ] - newb;
    unrb[ t ] = unrb[ t << 1 ] + unrb[ t << 1 | 1 ] - newb;
  }
  template< class T >
  void build( int t, int lb, int rb, const T &arr ){
    if( lb + 1 == rb ){
      if( arr[ lb ] == '(' ) unlb[ t ] = 1;
      else unrb[ t ] = 1;
      return;
    }
    int mid = lb + rb >> 1;
    build( t << 1, lb, mid, arr );
    build( t << 1 | 1, mid, rb, arr );
    pull( t );
  }
  tuple< int, int, int > query( int t, int lb, int rb, int ql, int qr ){
    if( qr <= lb or rb <= ql ) return make_tuple( 0, 0, 0 );
    if( ql <= lb and rb <= qr ) return make_tuple( maxlen[ t ], unlb[ t ], unrb[ t ] );
    int mid = lb + rb >> 1;
    auto tl = query( t << 1, lb, mid, ql ,qr );
    auto tr = query( t << 1 | 1, mid, rb, ql, qr );
    int a, b, c; tie( a, b, c ) = tl;
    int x, y, z; tie( x, y, z ) = tr;
    int nb = min( b, z );
    return make_tuple( a + x + nb, b + y - nb, c + z - nb );
  }
} tree;

string seq;

signed main(){
  ios::sync_with_stdio( 0 );
  cin >> seq;
  tree.build( 1, 0, seq.size(), seq );
  int M; cin >> M;
  for( int mi = 0; mi < M; ++mi ){
    int ql, qr; cin >> ql >> qr; --ql; // [ ql, qr )
    cout << 2 * get< 0 >( tree.query( 1, 0, seq.size(), ql, qr ) ) << "\n";
  }
  return 0;
}