Problem:
そこそこバランスのとれた括弧列
「そこそこバランスのとれた括弧列」とは，以下のいずれかの条件を満たす文字列である．
空文字列
そこそこバランスのとれた括弧列
A
が存在し，'(' を
1 個または 2 個
,
A
, ')' を
1 個または 2 個
をこの順に結合した文字列
空文字列でないそこそこバランスのとれた括弧列
A
,
B
が存在し，
A
,
B
をこの順に結合した文字列
たとえば，'())' や '())(()()' などはそこそこバランスのとれた括弧列であるが，'((' や '()))((()' などはそこそこバランスのとれた括弧列ではない．
'(' と ')' のみからなる文字列
S
が与えられる．
S
がそこそこバランスのとれた括弧列になるように括弧を追加する．ただし，括弧はどの位置に追加しても良い．追加する最小の括弧の数を求めよ．
Input
入力は最大 50 データセットからなる．各データセットは 1 行からなり，長さが
1
以上
2 × 10
5
以下の '(' と ')' のみからなる文字列が与えられる．
入力の終わりは，'#' からなる行で表される．文字列の長さの合計は
5 × 10
6
を超えない．
Output
各データセットについて，そこそこバランスのとれた括弧列にするために追加する最小の括弧の数を 1 行に出力せよ．
Sample Input
(()
())()(()
((()))))
))(()(
))()()))()(((())))))))((((()(
#
Output for the Sample Input
0
0
0
2
5

Submitted solutions:

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

// 与えられた括弧列 s に対して、前に left_add 個の '(' を追加すれば
// 「そこそこバランスのとれた括弧列」になるかどうかを判定する関数
bool check_balance(const string& s, int left_add) {
    int cur = left_add;
    int n = s.size();
    int i = 0;
    while (i < n) {
        if (s[i] == '(') {
            cur++;
            i++;
            continue;
        }

        // s[i] が ')' の場合
        if (cur == 0) return false;
        cur--;
        i++;

        // 連続する2つの ')' を許容（最大2個まで）
        if (i < n && s[i] == ')') {
            i++;
        }
    }
    return true;
}

// s をそこそこバランスにするために必要な '(' の最小追加数を求める関数
int min_add_left(const string& s) {
    int ok = s.size() * 2; 
    int ng = -1;

    while (abs(ok - ng) > 1) {
        int mid = (ok + ng) / 2;
        if (check_balance(s, mid)) {
            ok = mid;
        } else {
            ng = mid;
        }
    }

    return ok;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string s;
    while (getline(cin, s)) {
        if (s == "#") break;

        // 左側に追加する括弧数を求める
        int res = min_add_left(s);

        // 文字列を反転し、'(' と ')' を入れ替えて右側の補完を同様に処理
        reverse(s.begin(), s.end());
        for (char& c : s) {
            c = (c == '(' ? ')' : '(');
        }

        // 右側に追加する括弧数を求める
        res += min_add_left(s);

        // 結果を出力
        cout << res << '\n';
    }

    return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 3528
final_rank: 17

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

int f(string S) {
    int N = S.size();
    vector<int> A(N);
    int sum = 0, r = 0;
    for (int i = 0; i < N; i++) {
        if (S[i] == '(') {
            A[i] = 2;
        } else {
            if (i && A[i - 1] == -2) {
            } else {
                A[i] = -2;
            }
        }
        sum += A[i];
        r = min(r, sum);
    }
    r = -r;
    return (r + 1) / 2;
}

bool solve() {
    string S;
    cin >> S;
    if (S == "#") return false;
    int ans = 0;
    ans += f(S);
    reverse(S.begin(), S.end());
    for (char &c : S) c ^= '(' ^ ')';
    ans += f(S);
    cout << ans << '\n';
    return true;
}

int main() {
    while (solve()) {}
}
accuracy: 1
time_ms: 50
memory_kb: 4796
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define rrep(i, a, n) for(int i = a; i >= n; i--)
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
constexpr ll mod = 1000000007;
constexpr ll MOD = 998244353;
constexpr int IINF = 1001001001;
constexpr ll INF = 1LL<<60;

template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}


int main(){
    while(true){
        string s; cin >> s;
        if(s == "#") break;

        int n = (int)s.size();
        vector<pair<char, int>> rle;
        for(int i = 0; i < n; ){
            int j = i;
            rle.push_back({s[i], 0});
            while(j < n && s[i] == s[j]){
                rle.back().second++;
                j++;
            }
            i = j;
        }

        int l = 0, r = 0;
        int ans = 0;
        for(auto [c, cnt]: rle){
            if(c == '('){
                l += (cnt+1)/2;
                r += cnt;
            }else{
                if(r >= (cnt+1)/2){
                    r = r-(cnt+1)/2;
                    l = max(0, l-cnt);
                }else{
                    ans += (cnt+1)/2-r;
                    l = 0;
                    r = 0;
                }
            }
        }
        cout << ans+l << endl;
    }

    
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 7860
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
//using mint = modint998244353;

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 1e9;
const int MOD = 998244353;
const long long LINF = 4e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

vector<pair<char,int>> RLE(string s){
	vector<pair<char,int>> ans;
	if(s.size() == 0) return ans;
	int cnt = 1;
	for(int i = 1;i < s.size();i++){
		if(s[i] == s[i - 1]){
			cnt++;
			continue;
		}else{
			ans.push_back(make_pair(s[i - 1],cnt));
			cnt = 1;
		}
	}
	ans.push_back(make_pair(s[s.size() - 1],cnt));
	return ans;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while(1){
        string s;
        cin >> s;
        if(s == "#") return 0;
        vector<pair<char, int>> t = RLE(s);
        int mn = 0;
        int l = 0, r = 0;
        for(auto[c, cnt] : t){
            if(c == '('){
                l += (cnt + 1)/2;
                r += cnt;
            }else{
                // r こ余裕
                if((cnt + 1) / 2 <= r){
                    r -= (cnt + 1)/2;
                    l = max(0, l - cnt);
                }else{
                    cnt -= 2 * r;
                    r = 0;
                    l = 0;
                    mn += (cnt + 1)/2;
                }
                // if(l == 0 && r == 1){
                //     mn++;
                // }else{
                //     l = max(0, l - 2);
                //     r = max(1, r - 1);
                // }
            }
            // cout << mn << ' ' << l << ' ' << r << endl;
        }
        cout << mn + l << '\n';
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 8024
final_rank: 13

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#ifndef ONLINE_JUDGE
#define _GLIBCXX_DEBUG // 配列外参照のエラー
#endif

// スタンダードライブラリ
#include <bits/stdc++.h>
using namespace std;

// 多倍長整数
//  #if __has_include(<boost/multiprecision/cpp_int.hpp>)
//  #include <boost/multiprecision/cpp_int.hpp>
//  using lll =boost::multiprecision::int128_t;
//  #endif

// atcoder関連
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
using mint = modint998244353;
using MINT = modint1000000007;
#endif

// 型関連
using ll = long long;
using lint = long long;
using pll = pair<ll, ll>;
using plll = tuple<ll, ll, ll>;
using pii = pair<int, int>;
using piii = tuple<ll, ll, ll>;
template <class T> using prique = priority_queue<T>;

// 型定数
constexpr ll mod = 998244353;
constexpr ll MOD = 1000000007;
int inf = 2e9;
ll INF = 9e18;
#define endl '\n';

// 新規マクロ
#define all(a) (a).begin(), (a).end()
#define rep(i, N, limit) for (int i = (int)N; i < (int)limit; i++)

///////////////////// vector関連
template <class T, size_t n, size_t idx = 0>
auto make_vec(const size_t (&d)[n], const T &init) noexcept {
    if constexpr (idx < n)
        return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else
        return init;
}

template <class T, size_t n> auto make_vec(const size_t (&d)[n]) noexcept {
    return make_vec(d, T{});
}

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

/////////////////////////// print関連
template <typename T> void print(vector<T> A);
void print();
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail);
void print(string S);
template <typename T> void print(vector<vector<T>> &F);

////////////////////////////
inline string input();
inline ll I();
inline pll II();

/////////////////////出力関連
inline void Yes(bool f);

string rev_flip(string S) {
    string T = "";
    for (int i = S.size() - 1; i >= 0; i--) {
        if (S[i] == '(') {
            T += ')';
        } else {
            T += '(';
        }
    }
    return T;
}

int calc(string S) {
    int ans = 0;

    int l = 0, r = 0, c = 0;
    for (int i = 0; i < S.size(); i++) {
        if (S[i] == '(') {
            c++;
        } else {
            c--;
            if (i < S.size() - 1 && S[i + 1] == ')') {
                i++;
            }
        }
        ans=max(ans,-c);
    }
    
    
    return ans;
}

bool solve() {
    string S;
    cin >> S;
    if (S == "#") {
        return false;
    }
    print(calc(S) + calc(rev_flip(S)));

    return true;
}

///////////////////ここから//////////////////////
int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    while (solve())
        ;
}

////////////////////print/////////////////////////
// 1次元ベクトルを出力する
template <typename T> void print(vector<T> A) {
    if (A.size() == 0) {
        return;
    }
    for (size_t i = 0; i < A.size() - 1; i++) {
        cout << A[i] << ' ';
    }
    cout << A[A.size() - 1] << endl;
    return;
}

// 2次元ベクトルを出力する
template <typename T> void print(vector<vector<T>> &F) {
    for (size_t i = 0; i < F.size(); i++) {
        for (size_t j = 0; j < F[i].size(); j++) {
            cout << F[i][j];
            if (j < F[i].size() - 1) {
                cout << ' ';
            }
        }
        cout << endl;
    }
}

// 空白行を出力するprint
void print() { cout << endl; }

// 数値・文字列を空白区切りで出力する. print(a,b)など
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    cout << head;
    if (sizeof...(tail) != 0)
        cout << " ";
    print(forward<Tail>(tail)...);
}

void print(string S) { cout << S << endl; }

/////////////////////初期化///////////////////////

inline string input() {
    string S;
    cin >> S;
    return S;
}
inline ll I() {
    ll ret;
    cin >> ret;
    return ret;
}
inline pll II() {
    pll ret;
    cin >> ret.first >> ret.second;
    return ret;
}

//////////////出力関連

inline void Yes(bool f) {
    if (f) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 4676
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define all(a) (a).begin(), (a).end()
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define rrep(i, n) for (int i = (int)(n) - 1; 0 <= i; --i)
template <typename T> bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <typename T> bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
void solve();
string S;
signed main(){
  cin.tie(nullptr)->sync_with_stdio(false);
  cout << fixed << setprecision(20);
  int TESTCASES = 1<<30;
  //cin >> TESTCASES;
  while (TESTCASES--) {
    cin>>S;
    if(S=="#")break;
    solve();
  }
}
vector<pair<char,int>>rle(const string& s){
  int n=s.size(),l=0,r=0;
  vector<pair<char,int>>vp;
  while(l<n){
    while(r<n&&s[l]==s[r]){
      ++r;
    }
    vp.emplace_back(s[l],r-l);
    l=r;
  }
  return vp;
}
tuple<bool,int,int>check(int k){
  auto vp=rle(string(k,'(')+S);
  bool ok=1;
  int l=0,r=0;
  for(auto[ch,cnt]:vp){
    if(ch=='('){
      l+=(cnt+1)/2,r+=cnt;
    }else{
      l-=cnt,r-=(cnt+1)/2;
    }
    chmax(l,0);
    if(r<0){
      ok=0;
      break;
    }
  }
  return{ok,l,r};
}
void solve() {
  int lower=0,upper=2<<17,ans=1<<30;
  while(lower<upper){
    int mid=(lower+upper)/2;
    if(!get<0>(check(mid))){
      lower=mid+1;
    }else{
      upper=mid;
    }
  }
  cout<<lower+get<1>(check(lower))<<'\n';
}
accuracy: 1
time_ms: 130
memory_kb: 8144
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ull=unsigned long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define loop(n) for (int tjh = 0; tjh < (int)(n); tjh++)
constexpr int maxN=200000;
signed main() {
  cin.tie(0)->sync_with_stdio(0);
  cout<<fixed<<setprecision(16);
  string S;int N;vector<int>S0;S0.reserve(maxN);
  for(;cin>>S,S[0]!='#';){
    N=(int)S.size();
    S0.resize(0);
    int l=0;
    for(int i=1;i<N;i++){
      if(S[i]!=S[i-1]){
	if(S[i-1]=='(')S0.push_back(i-l);
	else S0.push_back(l-i);
	l=i;
      }
    }
    if(S[N-1]=='(')S0.push_back(N-l);
    else S0.push_back(l-N);
    int N0=(int)S0.size();
    l=-1;int r=maxN;
    auto f=[&](int v)->bool{
      array<int,2>a={(v+1)>>1,v};
      rep(i,N0){
	if(S0[i]>0){
	  a[0]+=(S0[i]+1)>>1;
	  a[1]+=S0[i];
	}else{
	  a[0]-=(-S0[i]);
	  a[1]-=(-S0[i]+1)>>1;
	  if(a[0]<0)a[0]=0;
	}
	if(a[1]<0)return false;
      }
      return true;
    };
    for(;r>l+1;){
      int m=midpoint(l,r);
      if(f(m))r=m;
      else l=m;
    }
    {
      array<int,2>a={(r+1)>>1,r};
      rep(i,N0){
	if(S0[i]>0){
	  a[0]+=(S0[i]+1)>>1;
	  a[1]+=S0[i];
	}else{
	  a[0]-=(-S0[i]);
	  a[1]-=(-S0[i]+1)>>1;
	  if(a[0]<0)a[0]=0;
	}
	if(a[1]<0)return 1;
      }
      cout<<r+a[0]<<'\n';
    }
  }
}
accuracy: 1
time_ms: 10
memory_kb: 4352
final_rank: 3

code_snippet: //#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,n) for (ll i=0;i<(ll)n;i++)
#define rrep(i,n) for (ll i=n-1;i>=(ll)0;i--)
#define loop(i,m,n) for(ll i=m;i<=(ll)n;i++)
#define rloop(i,m,n) for(ll i=m;i>=(ll)n;i--)
#define vl vector<long long>
#define vvl vector<vector<long long>>
#define vdbg(a) rep(ii,a.size()){cout<<a[ii]<<" ";}cout<<endl;
#define vvdbg(a) rep(ii,a.size()){rep(jj,a[ii].size()){cout<<a[ii][jj]<<" ";}cout<<endl;}
#define setdbg(a) for(const auto & ii:a){cout<<ii<<" ";}cout<<endl;
#define YES cout<<"Yes"<<endl;return 0;
#define NO cout<<"No"<<endl;return 0;
#define inf 4000000000000000000LL
#define mod 998244353LL
//#define mod 1000000007LL
random_device rnd;// 非決定的な乱数生成器
mt19937 mt(rnd());// メルセンヌ・ツイスタの32ビット版、引数は初期シード


//#include<boost/multiprecision/cpp_int.hpp>
//#define bbi boost::multiprecision::cpp_int

//#include<atcoder/lazysegtree>

//√の値が整数かを調べる
bool isSqrt(ll n) {
	if (n < 0) return false;
	ll sqrtN = static_cast<ll>(sqrt(n));
	return sqrtN * sqrtN == n;
}

//整数同士の累乗の計算をする。
ll power(ll A, ll B) {
	ll result = 1;
	for (ll i=0;i<B;i++){
		result *= A;
	}
	return result;
}

//素因数分解
vector<ll> makePrime(ll n){
	vector<ll> factors;
	while (n % 2 == 0) {
		factors.push_back(2);
		n /= 2;
	}
	for (ll i=3; i*i<=n;i+=2) {
		while (n%i == 0) {
			factors.push_back(i);
			n /= i;
		}
	}
	if (n > 2) {
		factors.push_back(n);
	}
	return factors;
}

//map形式で、nを素因数分解した値を返す
map<ll,ll> makeMapPrime(ll n){
	map<ll,ll> factors;
	while (n % 2 == 0) {
		factors[2]++;
		n /= 2;
	}
	for (ll i=3; i*i<=n;i+=2) {
		while (n%i == 0) {
			factors[i]++;
			n /= i;
		}
	}
	if (n > 2) {
		factors[n]++;
	}
	return factors;
}

// nのk乗をmodで割った余りを計算
ll power_mod(ll n, ll k){
	long long result = 1;
	while (k > 0){
		if ((k&1) ==1)result=(result*n)%mod;
		n=n*n%mod;
		k >>= 1;
	}
	return result;
}

//mod mにおけるaの逆元を計算
ll modinv(ll a, ll m) {
	ll b = m, u = 1, v = 0;
	while (b) {
		ll t = a / b;
		a -= t * b; swap(a, b);
		u -= t * v; swap(u, v);
	}
	u %= m; 
	if (u < 0) u += m;
	return u;
}

//場合の数 nCr を求める
ll ncr(ll n,ll r) {
	if(n<r)return 0;
	vvl dp(n+1,vl(r+1));
	rep (i,n+1)dp[i][0] = 1;
	rep (i,r+1)dp[i][i] = 1;
	loop (i,1,n){
		loop (j,1,min((ll)i-1,r)) {
			//nCr= n-1Cr-1 + n-1Cr
			dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
		}
	}
	return dp[n][r];
}

//受け取った文字列を、第2引数が0なら全て小文字に、1なら大文字に変換する関数
string cnvString(const string &str, int mode) {
	string result = str;
	if (mode == 0) {
		// 小文字に変換
		for (char &c : result) {
			c = tolower(c);
		}
	} else if (mode == 1) {
		// 大文字に変換
		for (char &c : result) {
			c = toupper(c);
		}
	}
	return result;
}

//第一引数で受け取った数を、第二引数で受け取った数の進数と見做して、第三引数の進数へ変換する。
string cnvBase(const string &str, ll from_base, ll to_base) {
	ll num = 0;
	//小文字があったら大文字に変換
	string num_str=cnvString(str,1);
	// 数値を10進数に変換
	for (char digit : num_str) {
		num = num * from_base + (isdigit(digit) ? digit - '0' : digit - 'A' + 10);
	}
	string result;
	// 数値を目的の基数に変換
	while (num > 0) {
		ll remainder = num % to_base;
		result.push_back(remainder < 10 ? remainder + '0' : remainder - 10 + 'A');
		num /= to_base;
	}
	// 結果を逆順にして返す
	reverse(result.begin(), result.end());
	return result.empty() ? "0" : result;
}

//底がaの対数xを計算。ただし小数点は繰り上げ。
ll logax(ll a, ll x){
	if(x<=1)return 0;
	ll result = 1;
	ll power = 1;
	while (power < (x+a-1) / a){
		power *= a;
		result++;
	}
	return result;
}

//第一引数を第二引数で割った余りを計算、割る数はint範囲
ll bigmd(const string &num, int md) {
	ll ans = 0;
	ll SIZ = 9; //9桁のチャンク
	ll base = 1000000000;//SIZ個の0
	rep(i,(num.size()-1)/SIZ+1){
		ll chunk = 0;
		ll l = i*SIZ;
		ll r = min((ll)num.size(),l+SIZ);
		if(r!=num.size()){
			ans = (ans*base+stoll(num.substr(l,r-l)))%md;
		}else{
			rep(i,r-l)ans*=10;
			ans=(ans+stoll(num.substr(l,r-l)))%md;
		}
	}
	return ans;
}

//受け取った2次元文字の外側に、文字pをコーティングする。
vector<string> pad(vector<string> &s,char p){
	ll h=s.size();
	ll w=s[0].size();
	vector<string> res(h+2,string(w+2,p));
	rep(i,h)rep(j,w)res[i+1][j+1]=s[i][j];
	return res;
}

//ax+by=cの整数解を得る ただし、cはgcd(a,b)の倍数でない場合、0,0になる
pair<ll,ll> ex_euclid(ll a,ll b,ll c){
	if(a<0||b<0||c<0){
		pair<ll,ll>ans=ex_euclid(abs(a),abs(b),abs(c));
		if(a<0)ans.first*=-1;
		if(b<0)ans.second*=-1;
		if(c<0)ans.first*=-1,ans.second*=-1;
		return ans;
	}
	if(c!=1){
		ll d=gcd(a,b);
		if(c%d!=0)return make_pair(0,0);
		pair<ll,ll>ans = ex_euclid(a/d,b/d,1);
		ans.first*=c/d;
		ans.second*=c/d;
		return ans;
	}
	if(a<b){
		pair<ll,ll>ans=ex_euclid(b,a,c);
		swap(ans.first,ans.second);
		return ans;
	}
	if(a==1&&b==0)return make_pair(1,0);
	else if(b==0) return make_pair(0,0);
	ll x,y;
	tie(x,y)=ex_euclid(b,a%b,c);
	pair<ll,ll> ans=make_pair(y,x-(a/b)*y);
	return ans;
}

//オイラーのトーシェント関数。N以下のNと互いに素な物の数を返す。
ll euler(ll n){
	unordered_map<ll,ll> factors;
	ll tmp=n;
	while (tmp % 2 == 0) {
		factors[2]++;
		tmp /= 2;
	}
	for (ll i=3; i*i<=tmp;i+=2) {
		while (tmp%i == 0) {
			factors[i]++;
			tmp/= i;
		}
	}
	if (tmp > 2)factors[tmp]++;
	ll ans=1;
	for(const auto & val:factors){
		ans*=power(val.first,val.second-1)*(val.first-1);
	}
	return ans;
}

// Union-Find
struct UnionFind {
	vector<int> par, siz;
	UnionFind(int n) : par(n, -1) , siz(n, 1) { }
	// 根を求める
	int root(int x) {
		if (par[x] == -1) return x;
		else return par[x] = root(par[x]);
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(int x, int y) {
		return root(x) == root(y);
	}
	// x を含むグループと y を含むグループとを併合する
	bool unite(int x, int y) {
		x = root(x), y = root(y);
		if (x == y) return false;
		if (siz[x] < siz[y]) swap(x, y);
		par[y] = x;
		siz[x] += siz[y];
		return true;
	}
	// x を含むグループのサイズ
	int size(int x) {
		return siz[root(x)];
	}
};

//重み付きUF
struct PotentialUnionFind {
	ll n;
	vl par, siz, pot;
	PotentialUnionFind(ll N) : par(N,-1) , siz(N,1) , pot(N,0){n=N;}
	// 根を求める
	ll root(ll x) {
		if (par[x] == -1) return x;
		ll tmp = root(par[x]);
		pot[x] += pot[par[x]];
		par[x] = tmp;
		return par[x];
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(ll x, ll y) {
		return root(x) == root(y);
	}
	//x よりいくつ大きい所に y があるか。根が一致しない場合は"0"
	ll potential(ll x,ll y){
		if(root(x) != root(y)) return 0;
		else return pot[y]-pot[x];
	}
	//x より w だけ大きい状態として y を併合。
	bool unite(ll x, ll y, ll w) {
		ll rx = root(x),ry = root(y);
		if (rx == ry) return false;
		w += pot[x]-pot[y];
		if (siz[rx] < siz[ry]) swap(rx, ry),w*=-1;
		par[ry] = rx;
		siz[rx] += siz[ry];
		siz[ry] = 0;
		pot[ry] = w;
		return true;
	}
	// x を含むグループのサイズ
	ll size(ll x) {
		return siz[root(x)];
	}
	//小さい順にUnionFindグラフを調整、O(n log n)
	void regulation(){
		vvl r(n);
		rep(i,n)r[root(i)].push_back(i);
		rep(i,n){
			if(r[i].size()==0)continue;
			ll mn = i;
			rep(j,r[i].size())if(pot[mn]>pot[r[i][j]])mn=r[i][j];
			siz[mn]=siz[i];
			siz[i]=0;
			ll tmp = pot[mn];
			rep(j,r[i].size()){
				pot[r[i][j]]-=tmp;
				par[r[i][j]] = mn;
			}
			par[mn]=-1;
		}
	}
	void debug(){
		rep(i,n)cout<<setw(4)<<left<<par[i]<<" ";
		cout<<endl;
		rep(i,n)cout<<setw(4)<<left<<pot[i]<<" ";
		cout<<endl;
	}
};

//分離可能UnionFind、経路圧縮をしない。
struct CuttingFind{
	vector<int> par, siz;
	CuttingFind(int n) : par(n, -1) , siz(n, 1) { }
	// 根を求める
	int root(int x) {
		if (par[x] == -1) return x;
		else return root(par[x]);
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(int x, int y) {
		return root(x) == root(y);
	}
	//根x と 根y のグループを併合する(お互い根ではない時、falseで何もしない)
	bool unite(int x, int y) {
		if (issame(x,y) || par[x] != -1 || par[y] != -1) {
			cout<<"error"<<endl;
			return false;
		}
		if (siz[x] < siz[y]) swap(x, y);
		par[y] = x;
		siz[x] += siz[y];
		return true;
	}
	//根の側から、その直系の子供を分離する。片方が根でもう片方が直系の子でなければならない。
	bool separate(int x,int y){
		if(par[y]==-1)swap(x,y);
		if(par[y]!=x||par[x]!=-1){
			cout<<"error2"<<endl;
			return false;
		}
		siz[x] -= siz[y];
		par[y]=-1;
		return true;
	}
	// x を含むグループのサイズを求める
	int size(int x) {
		return siz[root(x)];
	}
};
//セグ木,乗せる値の型が必要
template<typename T>
struct SegTree{
	ll size;
	ll tall;
	vector<T> data;
	function<T(T,T)> p;
	//セグ木に乗せる値の初期値をa配列にし、putの関数をセグ木に乗せる、dをデフォルト値に。
	SegTree(vector<T> a,function<T(T,T)> put,T d) : data(power(2,logax(2,a.size())+1)) {
		size = data.size()/2;
		tall=logax(2,size)+1;
		p=put;
		ll tmp=size;
		data = vector<T>(size*2,d);
		while(tmp!=0){
			if(tmp==size)rep(i,a.size())data[tmp+i]=a[i];
			else rep(i,tmp) data[tmp+i]=p(data[2*(tmp+i)],data[2*(tmp+i)+1]);
			tmp/=2;
		}
	}
	//更新、t番目の値をxにする。
	void update(ll t,T x){
		t+=size;
		while(t!=0){
			if(t>=size)data[t]=x;
			else data[t]=p(data[2*t],data[2*t+1]);
			t/=2;
		}
	}
	//取得、l~r区間内の評価値を取得する。
	T get(ll l,ll r){
		//lとrが範囲外なら範囲内に正す
		l=max(0LL,l);
		r=min(r,size-1);
		r++;
		T ans=data[0];
		ll pos=l+size;
		ll wid=1;
		//出来る限り上に上げきる。
		while(l+(wid*2)<=r){
			while(l%(wid*2)==0&&l+(wid*2)<=r)pos/=2,wid*=2;
			ans=p(ans,data[pos]);
			pos++;
			l+=wid;
		}
		//上げ終わったので今度は下げる
		while(l!=r){
			while(l+wid>r)pos*=2,wid/=2;
			ans=p(ans,data[pos]);
			pos++;
			l+=wid;
		}
		return ans;
	}
	//セグ木デバッグ用、丸ごと出力
	void print(){
		rep(i,size)cout<<setw(7)<<left<<i;
		cout<<endl;
		ll pos=size;
		rep(i,tall){
			rep(j,size){
				if(j%power(2,i)==0)cout<<setw(7)<<left<<data[pos],pos++;
				else cout<<"       ";
			}
			pos/=4;
			cout<<endl;
		}
	}
};

//グリッド問題等用
vl dx={1,0,-1,0};
vl dy={0,1,0,-1};

ll solve(){
	string s;
	cin>>s;
	if(s=="#"){return 1;}

	ll ans=0;

	//できる限り閉じ括弧を消しに行く場合に残る閉じ括弧の個数を求める。
	s.push_back('(');
	ll closecnt=0;
	ll opencnt=0;
	rep(i,s.size()){
		if(s[i]=='('){
			//今溜まってる閉じ括弧に対応させるのに必要な個数。
			ll tmp = (closecnt+1)/2;
			closecnt=0;

			tmp-=opencnt;
			opencnt=0;

			if(tmp<0)opencnt=-tmp;
			else ans+=tmp;
			
			opencnt++;
		}else {
			closecnt++;
		}
	}
	s.pop_back();

	reverse(s.begin(),s.end());
	rep(i,s.size()){
		if(s[i]=='(')s[i]=')';
		else s[i]='(';
	}

	s.push_back('(');
	closecnt=0;
	opencnt=0;
	rep(i,s.size()){
		if(s[i]=='('){
			//今溜まってる閉じ括弧に対応させるのに必要な個数。
			ll tmp = (closecnt+1)/2;
			closecnt=0;

			tmp-=opencnt;
			opencnt=0;

			if(tmp<0)opencnt=-tmp;
			else ans+=tmp;
			
			opencnt++;
		}else {
			closecnt++;
		}
	}
	s.pop_back();
	

	cout<<ans<<endl;
	return 0;
}

//メイン
int main(){
	while(solve()==0);
	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3532
final_rank: 9

code_snippet: #include <iostream>
#include <iomanip>
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
// #include "Src/Utility/BinarySearch.hpp"
// #include "Src/Sequence/CompressedSequence.hpp"
// #include "Src/Sequence/RunLengthEncoding.hpp"
// using namespace zawa;
// #include "atcoder/modint"
// using mint = atcoder::modint998244353;
std::string S;
bool solve() {
    std::cin >> S;
    if (S == "#") return false;
    std::vector<std::pair<int, int>> r;
    for (char c : S) {
        int v = c == '(' ? 1 : -1;
        if (r.empty() or v != r.back().first) r.push_back({v, 1});
        else r.back().second++;
    }
    int bal = 0, redL = 0, redR = 0, ans = 0;
    for (auto [v, c] : r) {
        bal += v * c;
        if (v == 1) redL += c / 2;
        else if (v == -1) redR += c / 2;
        else assert(false);
        if (bal < 0) {
            int op = std::min(-bal, redR);
            redR -= op;
            bal += op;
            assert(bal <= 0);
            assert(redR >= 0);
            op = -bal;
            bal += op;
            ans += op;
        }
        assert(bal >= 0);
        redL = std::min(redL, bal);
    }
    if (bal > 0) {
        int op = std::min(redL, bal);
        bal -= op;
        redL -= op;
        assert(redL >= 0 and bal >= 0);
        ans += bal;
    }
    std::cout << ans << '\n';
    return true;
}
int main() {
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);
    while (solve()) ;
}
accuracy: 1
time_ms: 10
memory_kb: 7724
final_rank: 12

code_snippet: #include <iostream>
#include <numeric>
#include <cassert>
#include <vector>
#include <utility>
std::string S;
bool solve() {
    std::cin >> S;
    if (S == "#") return false;
    std::vector<std::pair<int, int>> R;
    for (int i = 0 ; i < (int)S.size() ; i++) {
        int b = S[i] == '(' ? 1 : -1;
        if (R.empty() or R.back().first != b) R.push_back({b, 1});
        else R.back().second++;
    }
    int bal = 0, ans = 0, redL = 0, redR = 0;
    for (auto [b, c] : R) {
        bal += b * c;
        if (b == 1) {
            redL += c / 2;
        }
        else if (b == -1) {
            redR += c / 2;
        }
        else assert(false);
        if (bal < 0) { // Rを減らす
            int op = std::min(redR, -bal);
            bal += op;
            redR -= op;
            assert(bal <= 0);
            ans += -bal;
            bal = 0;
        }
        assert(bal >= 0);
        redL = std::min(bal, redL);
    }
    if (bal > 0) {
        int op = std::min(redL, bal);
        redL -= op;
        bal -= op;
        assert(bal >= 0);
        ans += bal;
    }
    std::cout << ans << '\n';
    return true;
}
int main() {
	while (solve()) ;
}
accuracy: 1
time_ms: 50
memory_kb: 6368
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
#define ALL(v) v.begin(),v.end()
#define dbg(x) cerr << #x << ": " << (x) << endl;

int sum[4][1 << 10][1 << 10];

void solve()
{
    string s;
    cin >> s;
    if (s == "#") exit(0);
    int n = s.size(), ans = 0;
    {
        int b0 = 0;
        while (b0 < n && s[b0] == ')') ++b0;
        ans += (b0 + 1) / 2;
        if (b0 == n)
        {
            cout << ans << endl;
            return;
        }
        s = s.substr(b0, n - b0);
        n = s.size();
        b0 = 0;
        while (n - 1 - b0 >= 0 && s[n - 1 - b0] == '(') ++b0;
        ans += (b0 + 1) / 2;
        if (b0 == n)
        {
            cout << ans << endl;
            return;
        }
        s = s.substr(0, n - b0);
        n = s.size();
    }
    for (int _t = 0; _t < 2; _t++)
    {
        vector<pair<int, char>> lg;
        for (int l = 0, r = 0; l < n;)
        {
            while (r < n && s[r] == s[l]) ++r;
            lg.emplace_back(r - l, s[l]);
            l = r;
        }
        vector<int> st;
        for (auto [len, c] : lg)
        {
            int cnt = (len + 1) / 2;
            if (c == '(')
            {
                st.push_back(len);
            }
            else
            {
                while (!st.empty() && cnt > 0)
                {
                    int tmp = min(st.back(), cnt);
                    st[st.size() - 1] -= tmp;
                    cnt -= tmp;
                    if (st.back() == 0) st.pop_back();
                }
                ans += cnt;
            }
        }
        reverse(s.begin(), s.end());
        for (int i = 0; i < n; ++i)
        {
            if (s[i] == '(') s[i] = ')';
            else s[i] = '(';
        }
    }
    cout << ans << endl;
}

int main() {
    while (true) solve();
}
accuracy: 1
time_ms: 70
memory_kb: 6744
final_rank: 16

code_snippet: #include <bits/stdc++.h>
    using namespace std;
    
    template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
    template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
    #define rep(i,n) for (int i = 0; i < (n); ++i)

    typedef long long ll;
    typedef unsigned long long ull;
    using P=pair<ll,ll>;
    using tp=tuple<ll,ll,ll>;
    const int INF=1001001001;
    const ll INFL=1e18;
    const int mod=998244353;


    bool solve(){
		string s;
		cin>>s;
		if(s=="#")return false;
		int n=s.size();
		int ans=0;
		
		{
			int open=0,mn=0;
			rep(i,n){
				if(s[i]=='('){
					open++;
				}else{
					open--;
					if(i+1<n&&s[i+1]==')'){
						i++;
					}
				}
				chmin(mn,open);
			}
			ans+=-mn;
		}
		{
			int close=0,mn=0;
			for(int i=n-1;i>=0;i--){
				if(s[i]==')'){
					close++;
				}else{
					close--;
					if(i-1>=0&&s[i-1]=='('){
						i--;
					}
				}
				chmin(mn,close);
			}
			ans+=-mn;
		}
		cout<<ans<<endl;
		return true;
    }

    int main(){
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);

		while(1){
			if(!solve())return false;
		}
		
        return 0;
    }
accuracy: 1
time_ms: 10
memory_kb: 3940
final_rank: 2

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

static bool DP[2501][2501] = {};

int main() {
while(1) {
    string S;
    cin >> S;
    if (S == "#") return 0;
    int N = S.size();
    vector<int> V(N);
    rep(i,0,N) {
        if (S[i] == '(') V[i] = 0;
        else V[i] = 1;
    }
    int ANS = 0;
    int NOW = 0;
    int MIN = 0;
    for (int i = 0; i < N; ) {
        if (i == N - 1) {
            if (V[i] == 0) NOW++;
            else NOW--;
            i++;
        }
        else if (V[i] == 1 && V[i + 1] == 1) {
            NOW--;
            i+=2;
        }
        else {
            if (V[i] == 0) NOW++;
            else NOW--;
            i++;
        }
        chmin(MIN, NOW);
    }
    ANS += -MIN;
    MIN = NOW = 0;
    reverse(ALL(V));
    rep(i,0,N) V[i] = 1 - V[i];
    for (int i = 0; i < N; ) {
        if (i == N - 1) {
            if (V[i] == 0) NOW++;
            else NOW--;
            i++;
        }
        else if (V[i] == 1 && V[i + 1] == 1) {
            NOW--;
            i+=2;
        }
        else {
            if (V[i] == 0) NOW++;
            else NOW--;
            i++;
        }
        chmin(MIN, NOW);
    }
    ANS += -MIN;
    cout << ANS << endl;

}
}
accuracy: 1
time_ms: 60
memory_kb: 4688
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef vector<ll> vi;
typedef vector<vi> vvi;
typedef vector<vvi> vvvi;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef vector<vvb> vvvb;
typedef vector<vvvb> vvvvb;
typedef pair<ll,ll> pi;
typedef pair<ll,pi> ppi;
#define FOR(i,l,r) for(ll i=l;i<r;i++)
#define REP(i,n) FOR(i,0,n)
#define RFOR(i,l,r) for(ll i=r-1;i>=l;i--)
#define RREP(i,n) RFOR(i,0,n)
#define sz(A) (ll)(A.size())
#define ALL(A) A.begin(),A.end()
#define LB(A,x) (ll)(lower_bound(ALL(A),x)-A.begin())
#define UB(A,x) (ll)(upper_bound(ALL(A),x)-A.begin())
#define COU(A,x) (UB(A,x)-LB(A,x))
#define F first
#define S second
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.F<<" "<<p.S;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.F>>p.S;return is;}
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){REP(i,sz(v))os<<v[i]<<(i+1!=sz(v)?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<class T>bool chmax(T&a,T b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T&a,T b){if(b<a){a=b;return 1;}return 0;}
const ll mod=998244353;
template<const long long int mod=998244353>
struct modint{
  using mint=modint<mod>;
  long long int x;
  modint(long long int _x=0):x(_x%mod){if(x<0)x+=mod;}
  long long int val(){return x;}
  mint&operator=(const mint&a){x=a.x;return *this;}
  mint&operator+=(const mint&a){x+=a.x;if(x>=mod)x-=mod;return *this;}
  mint&operator-=(const mint&a){x-=a.x;if(x<0)x+=mod;return *this;}
  mint&operator*=(const mint&a){x*=a.x;x%=mod;return *this;}
  friend mint operator+(const mint&a,const mint&b){return mint(a)+=b;}
  friend mint operator-(const mint&a,const mint&b){return mint(a)-=b;}
  friend mint operator*(const mint&a,const mint&b){return mint(a)*=b;}
  mint operator-()const{return mint(0)-*this;}
  mint pow(long long int n){
    if(!n)return 1;
    mint a=1;
    mint _x=x;
    while(n){
      if(n&1)a*=_x;
      _x=_x*_x;n>>=1;
    }
    return a;
  }
  mint inv(){return pow(mod-2);}
  mint&operator/=(mint&a){return *this*=a.inv();}
  friend mint operator/(const mint&a,mint b){return mint(a)/=b;}
};
using mint=modint<998244353>;
#include<bits/stdc++.h>
using namespace std;
struct dsu{
    private:
	vector<int>parent;
    public:
    dsu()=default;
	  dsu(size_t n):parent(n,-1){}
	  int leader(int i){
		    if(parent[i]<0)return i;
		    return parent[i]<0?i:(parent[i]=leader(parent[i]));
	  }
	  int merge(int a,int b){
		    a=leader(a);
		    b=leader(b);
		    if (a!=b){
			      if(-parent[a]<-parent[b])swap(a,b);
			      parent[a]+=parent[b];
			      parent[b]=a;
		    }
		    return a;
	  }
	  bool same(int a,int b){return leader(a)==leader(b);}
	  int size(int i){return -parent[leader(i)];}
	  vector<vector<int>>groups(){
	      size_t n=parent.size();
	      vector<vector<int>>A(n);
	      for(int i=0;i<n;i++)A[leader(i)].emplace_back(i);
	      vector<vector<int>>res;
	      for(auto a:A)if(a.size())res.emplace_back(a);
	      return res;
	  }
};
int main(){
    while(1){
        string S;cin>>S;
        if(S=="#")return 0;
        ll ans=0,l=0,r=0;
        REP(i,sz(S)){
            ll j=i;
            while(i<sz(S)&&S[i]==S[j])i++;
            ll d=i-j;
            if(S[j]=='(')l+=(d+1)/2,r+=d;
            else l-=d,r-=(d+1)/2;
            chmax(l,0LL);
            if(r<0){ans-=r;r=0;}
            i--;
        }
        ans+=l;
        cout<<ans<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3548
final_rank: 7

code_snippet: // C++ includes used for precompiling -*- C++ -*-
// Copyright (C) 2003-2013 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.
/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */
// 17.4.1.2 Headers
// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif

using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
constexpr int INF = 1000000000;
constexpr int64_t llINF = 3000000000000000000;
constexpr double eps = 1e-10;
const double pi = acos(-1);
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll modpow(ll a, ll b, ll m) {
    ll res = 1;
    while (b) {
        if (b & 1) {
            res *= a;
            res %= m;
        }
        a *= a;
        a %= m;
        b >>= 1;
    }
    return res;
}
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
template <class T>
struct Matrix {
    int n;
    vector<vector<T>> m;
    Matrix() : Matrix(0) {}
    Matrix(int x) : Matrix(vector<vector<T>>(x, vector<T>(x, 0))) {}
    Matrix(const vector<vector<T>> &a) {
        n = a.size();
        m = a;
    }
    vector<T> &operator[](int i) { return m[i]; }
    const vector<T> &operator[](int i) const { return m[i]; }
    static Matrix identity(int x) {
        Matrix res(x);
        for (int i = 0; i < x; i++) res[i][i] = 1;
        return res;
    }
    Matrix operator+(const Matrix &a) const {
        Matrix x = (*this);
        return x += a;
    }
    Matrix operator*(const Matrix &a) const {
        Matrix x = (*this);
        return x *= a;
    }
    Matrix &operator+=(const Matrix &a) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                res[i][j] = m[i][j] + a[i][j];
            }
        }
        m = res.m;
        return *this;
    }
    Matrix &operator*=(const Matrix &a) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    res[i][j] += m[i][k] * a[k][j];
                }
            }
        }
        m = res.m;
        return *this;
    }
    Matrix pow(ll b) const {
        Matrix x = *this, res = identity(n);
        while (b) {
            if (b & 1) {
                res *= x;
            }
            x *= x;
            b >>= 1;
        }
        return res;
    }
};
template <class S, S (*op)(S, S), S (*e)()>
struct segtree {
    int siz = 1;
    vector<S> dat;
    segtree(int n) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S> &a) {
        while (siz < a.size()) siz <<= 1;
        dat = vector<S>(siz << 1, e());
        for (int i = 0; i < a.size(); i++) dat[siz + i] = a[i];
        for (int i = siz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void set(int p, S x) {
        p += siz;
        dat[p] = x;
        while (p > 0) {
            p >>= 1;
            dat[p] = op(dat[2 * p], dat[2 * p + 1]);
        }
    }
    void add(int p, S x) { set(p, get(p) + x); }
    S get(int p) { return dat[p + siz]; }
    S prod(int l, int r) {
        S vl = e(), vr = e();
        l += siz, r += siz;
        while (l < r) {
            if (l & 1) vl = op(vl, dat[l++]);
            if (r & 1) vr = op(dat[--r], vr);
            l >>= 1, r >>= 1;
        }
        return op(vl, vr);
    }
    S all_prod() { return dat[1]; }
};

template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};
template <class T, T (*op)(T, T), T (*e)()>
struct sparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    sparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            for (int j = 0; j + (1 << i) <= (1 << len); j++) {
                table[i][j] = op(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
            }
        }
        logtable.resize(v.size() + 1);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        assert(l <= r);
        if (l == r) return e();
        int len = logtable[r - l];
        return op(table[len][l], table[len][r - (1 << len)]);
    }
};
template <class T, T (*op)(T, T), T (*e)()>
struct disjointsparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    disjointsparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len, e()));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            int shift = 1 << i;
            for (int j = 0; j < (int)v.size(); j += shift << 1) {
                int t = min(j + shift, (int)v.size());
                table[i][t - 1] = v[t - 1];
                for (int k = t - 2; k >= j; k--) table[i][k] = op(v[k], table[i][k + 1]);
                if (v.size() <= t) break;
                table[i][t] = v[t];
                int r = min(t + shift, (int)v.size());
                for (int k = t + 1; k < r; k++) table[i][k] = op(table[i][k - 1], v[k]);
            }
        }
        logtable.resize(1 << len);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        if (l == r) return e();
        if (l >= --r) return table[0][l];
        int len = logtable[l ^ r];
        return op(table[len][l], table[len][r]);
    };
};
struct lca_tree {
    int n, size;
    vector<vector<int>> par;
    vector<int> depth;
    lca_tree(vector<vector<int>> g, int root = 0) : n((int)g.size()), size(log2(n) + 2), par(size, vector<int>(n, -1)), depth(vector<int>(n, n)) {
        queue<int> que;
        depth[root] = 0;
        que.push(root);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            for (int i : g[p]) {
                if (depth[i] > depth[p] + 1) {
                    depth[i] = depth[p] + 1;
                    par[0][i] = p;
                    que.push(i);
                }
            }
        }
        for (int k = 0; k < size - 1; k++) {
            for (int i = 0; i < n; i++) {
                if (par[k][i] == -1)
                    par[k + 1][i] = -1;
                else
                    par[k + 1][i] = par[k][par[k][i]];
            }
        }
    }
    int query(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int k = size - 1; k >= 0; k--) {
            if (((depth[v] - depth[u]) >> k) & 1) v = par[k][v];
            if (u == v) return u;
        }
        for (int k = size - 1; k >= 0; k--) {
            if (par[k][u] != par[k][v]) {
                u = par[k][u];
                v = par[k][v];
            }
        }
        return par[0][u];
    }
    int dist(int u, int v) {
        int l = query(u, v);
        return depth[u] + depth[v] - 2 * depth[l];
    }
};
struct UnionFind {
    vector<int> par, siz, es;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        es.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
            es[i] = 0;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) {
            es[x]++;
            return false;
        }
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];
        es[x] += es[y] + 1;
        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
    int edges(int x) { return es[find(x)]; }
};
struct Mo {
    int n;
    vector<pair<int, int>> lr;

    explicit Mo(int n) : n(n) {}

    void add(int l, int r) { /* [l, r) */ lr.emplace_back(l, r); }

    template <typename AL, typename AR, typename EL, typename ER, typename O>
    void build(const AL &add_left, const AR &add_right, const EL &erase_left, const ER &erase_right, const O &out) {
        int q = (int)lr.size();
        int bs = n / min<int>(n, sqrt(q));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = lr[a].first / bs, bblock = lr[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? lr[a].second > lr[b].second : lr[a].second < lr[b].second;
        });
        int l = 0, r = 0;
        for (auto idx : ord) {
            while (l > lr[idx].first) add_left(--l);
            while (r < lr[idx].second) add_right(r++);
            while (l < lr[idx].first) erase_left(l++);
            while (r > lr[idx].second) erase_right(--r);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A &add, const E &erase, const O &out) {
        build(add, add, erase, erase, out);
    }
};
template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazy_segtree {
    int _n, sz = 1;
    vector<S> dat;
    vector<F> lazy;
    lazy_segtree(vector<S> a) : _n(int(a.size())) {
        while (sz < _n) sz <<= 1;
        dat.resize(sz * 2, e());
        lazy.resize(sz * 2, id());
        rep(i, _n) dat[sz + i] = a[i];
        for (int i = sz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void eval(int k) {
        dat[k] = mapping(lazy[k], dat[k]);
        if (k < sz) {
            lazy[k * 2] = composition(lazy[k], lazy[k * 2]);
            lazy[k * 2 + 1] = composition(lazy[k], lazy[k * 2 + 1]);
        }
        lazy[k] = id();
    }
    void apply(int a, int b, F f, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = composition(f, lazy[k]);
            eval(k);
            return;
        }
        int m = (l + r) >> 1;
        apply(a, b, f, 2 * k, l, m);
        apply(a, b, f, 2 * k + 1, m, r);
        dat[k] = op(dat[2 * k], dat[2 * k + 1]);
    }
    S prod(int a, int b, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return e();
        if (a <= l && r <= b) return dat[k];
        int m = (l + r) >> 1;
        S vl = prod(a, b, 2 * k, l, m);
        S vr = prod(a, b, 2 * k + 1, m, r);
        return op(vl, vr);
    }
};

template <class S, S (*op)(S, S), S (*e)()>
struct dual_segtree {
    int sz = 1, log = 0;
    vector<S> lz;
    dual_segtree(vector<S> a) {
        int n = a.size();
        while (sz < n) {
            sz <<= 1;
            log++;
        }
        lz.assign(sz << 1, e());
        for (int i = 0; i < n; i++) lz[i + sz] = a[i];
    }
    void push(int k) {
        int b = __builtin_ctz(k);
        for (int d = log; d > b; d--) {
            lz[k >> d << 1] = op(lz[k >> d << 1], lz[k >> d]);
            lz[k >> d << 1 | 1] = op(lz[k >> d << 1 | 1], lz[k >> d]);
            lz[k >> d] = e();
        }
    }
    void apply(int l, int r, S x) {
        l += sz, r += sz;
        push(l);
        push(r);
        while (l < r) {
            if (l & 1) {
                lz[l] = op(lz[l], x);
                l++;
            }
            if (r & 1) {
                r--;
                lz[r] = op(lz[r], x);
            }
            l >>= 1, r >>= 1;
        }
    }
    S get(int k) {
        k += sz;
        S res = e();
        while (k) {
            res = op(res, lz[k]);
            k >>= 1;
        }
        return res;
    }
};
ll modinv(int x, int modulo) {
    int a = x, b = modulo, u = 1, v = 0, t;
    while (b > 0) {
        t = a / b;
        swap(a -= t * b, b);
        swap(u -= t * v, v);
    }
    return (u >= 0 ? u % modulo : (modulo - (-u) % modulo) % modulo);
}
struct auxiliary_tree : lca_tree {
    vector<int> in;
    vector<vector<int>> G;
    auxiliary_tree(vector<vector<int>> &g) : lca_tree(g), in((int)g.size()), G((int)g.size()) {
        int t = 0;
        dfs(0, -1, t, g);
    }
    void dfs(int v, int p, int &t, vector<vector<int>> &g) {
        in[v] = t++;
        for (auto u : g[v]) {
            if (u != p) dfs(u, v, t, g);
        }
    }
    using lca_tree::depth;
    pair<int, vector<int>> query(vector<int> vs, bool decending = false) {
        // decending: only parent to child
        assert(!vs.empty());
        sort(vs.begin(), vs.end(), [&](int a, int b) { return in[a] < in[b]; });
        int m = vs.size();
        stack<int> st;
        st.push(vs[0]);
        for (int i = 0; i < m - 1; i++) {
            int w = lca_tree::query(vs[i], vs[i + 1]);
            if (w != vs[i]) {
                int l = st.top();
                st.pop();
                while (!st.empty() && depth[w] < depth[st.top()]) {
                    if (!decending) G[l].push_back(st.top());
                    G[st.top()].push_back(l);
                    l = st.top();
                    st.pop();
                }
                if (st.empty() || st.top() != w) {
                    st.push(w);
                    vs.push_back(w);
                }
                if (!decending) G[l].push_back(w);
                G[w].push_back(l);
            }
            st.push(vs[i + 1]);
        }
        while (st.size() > 1) {
            int x = st.top();
            st.pop();
            if (!decending) G[x].push_back(st.top());
            G[st.top()].push_back(x);
        }
        // {root,vertex_list}
        return make_pair(st.top(), vs);
    }
    void clear(vector<int> vs) {
        for (int v : vs) G[v].clear();
    }
};
struct LowLink {
    vector<vector<int>> g;
    vector<int> ord, low, out;
    vector<bool> used;
    vector<pair<int, int>> bridge;
    vector<pair<int, int>> articulation;
    int unions;
    LowLink(vector<vector<int>> g) : g(g) {
        int n = (int)g.size();
        ord.resize(n);
        low.resize(n);
        out.resize(n);
        used.resize(n);
        unions = 0;
        int t = 0;
        for (int i = 0; i < n; i++) {
            if (!used[i]) {
                dfs(i, t, -1);
                unions++;
            }
        }
    }
    void dfs(int v, int &t, int par) {
        used[v] = true;
        ord[v] = t++, low[v] = ord[v];
        int cnt = 0;
        bool par_back = false;
        for (int to : g[v]) {
            if (!used[to]) {
                dfs(to, t, v);
                low[v] = min(low[v], low[to]);
                if (ord[v] < low[to]) bridge.push_back(minmax(v, to));
                if (ord[v] <= low[to]) cnt++;
            } else if (to != par || par_back) {
                low[v] = min(low[v], ord[to]);
            } else
                par_back = true;
        }
        if (par != -1) cnt++;
        if (cnt >= 2) articulation.push_back({v, cnt});
        out[v] = t;
    }
};
void solve(string s){
    int n=s.size();
    vector<int>v{0};
    rep(i,n){
        if(s[i]=='('){
            if(v.size()%2==1)v.back()++;
            else v.push_back(1);
        }
        else{
            if(v.size()%2==0)v.back()++;
            else v.push_back(1);
        }
    }
    if(v.size()%2==1)v.push_back(0);
    stack<int>mi,ma;
    int ans=0;
    rep(i,v.size()/2){
        int a=v[2*i],b=v[2*i+1];
        //minimum:(b+1)/2 maximum:2*b
        //digest b
        mi.push(a),ma.push(a);
        while(ma.size()&&b){
            int k=ma.top();
            ma.pop();
            if(k>(b+1)/2){
                k-=(b+1)/2;
                b=0;
                ma.push(k);
                break;
            }
            b-=2*k;
        }
        if(b){
            ans+=(b+1)/2;
            while(ma.size())ma.pop();
            while(mi.size())mi.pop();
            continue;
        }
        //ma:survived
        b=v[2*i+1];
        while(mi.size()&&b){
            int k=mi.top();
            mi.pop();
            if(k>2*b){
                k-=2*b;
                mi.push(k);
                break;
            }
            b-=(k+1)/2;
        }
    }
    while(!mi.empty()){
        int k=mi.top();
        mi.pop();
        ans+=(k+1)/2;
    }
    cout<<ans<<endl;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n,m,k,d,b;
    string s;
    while(cin>>s){
        if(s=="#")break;
    solve(s);
    }
}
accuracy: 1
time_ms: 10
memory_kb: 5328
final_rank: 5

code_snippet: // g++-13 1.cpp -std=c++17 -O2 -I .
#include <bits/stdc++.h>
using namespace std;

#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/tag_and_trait.hpp>
using namespace __gnu_pbds;

using ll = long long;
using ld = long double;
 
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vld = vector<ld>;
using vvld = vector<vld>;
using vst = vector<string>;
using vvst = vector<vst>;
 
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define pq_big(T) priority_queue<T,vector<T>,less<T>>
#define pq_small(T) priority_queue<T,vector<T>,greater<T>>
#define all(a) a.begin(),a.end()
#define rep(i,start,end) for(ll i=start;i<(ll)(end);i++)
#define per(i,start,end) for(ll i=start;i>=(ll)(end);i--)
#define uniq(a) sort(all(a));a.erase(unique(all(a)),a.end())

random_device seed;
mt19937_64 randint(seed());

ll grr(ll mi, ll ma) { // [mi, ma)
    return mi + randint() % (ma - mi);
}

void solve(string s){
  int n=s.size();
  int ans=0;
  int sum=0,mn=0;
  rep(i,0,n){
    if(s[i]==')'){
      sum--;
      if(i+1<n&&s[i+1]==')')i++;
      mn=min(mn,sum);
    }
    else{
      sum++;
    }
  }

  ans+=-mn;

  sum=0,mn=0;
  per(i,n-1,0){
    if(s[i]=='('){
      sum--;
      if(i>0&&s[i-1]=='(')i--;
      mn=min(mn,sum);
    }
    else{
      sum++;
    }
  }

  ans+=-mn;
  cout<<ans<<endl;
}

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  while(true){
    string s;cin>>s;
    if(s=="#")return 0;
    solve(s);
  }
}
accuracy: 1
time_ms: 10
memory_kb: 3656
final_rank: 1

code_snippet: // C++ includes used for precompiling -*- C++ -*-
// Copyright (C) 2003-2013 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.
/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */
// 17.4.1.2 Headers
// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif

using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
constexpr int INF = 1000000000;
constexpr int64_t llINF = 3000000000000000000;
constexpr double eps = 1e-10;
const double pi = acos(-1);
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll modpow(ll a, ll b, ll m) {
    ll res = 1;
    while (b) {
        if (b & 1) {
            res *= a;
            res %= m;
        }
        a *= a;
        a %= m;
        b >>= 1;
    }
    return res;
}
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
template <class T>
struct Matrix {
    int n;
    vector<vector<T>> m;
    Matrix() : Matrix(0) {}
    Matrix(int x) : Matrix(vector<vector<T>>(x, vector<T>(x, 0))) {}
    Matrix(const vector<vector<T>> &a) {
        n = a.size();
        m = a;
    }
    vector<T> &operator[](int i) { return m[i]; }
    const vector<T> &operator[](int i) const { return m[i]; }
    static Matrix identity(int x) {
        Matrix res(x);
        for (int i = 0; i < x; i++) res[i][i] = 1;
        return res;
    }
    Matrix operator+(const Matrix &a) const {
        Matrix x = (*this);
        return x += a;
    }
    Matrix operator*(const Matrix &a) const {
        Matrix x = (*this);
        return x *= a;
    }
    Matrix &operator+=(const Matrix &a) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                res[i][j] = m[i][j] + a[i][j];
            }
        }
        m = res.m;
        return *this;
    }
    Matrix &operator*=(const Matrix &a) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    res[i][j] += m[i][k] * a[k][j];
                }
            }
        }
        m = res.m;
        return *this;
    }
    Matrix pow(ll b) const {
        Matrix x = *this, res = identity(n);
        while (b) {
            if (b & 1) {
                res *= x;
            }
            x *= x;
            b >>= 1;
        }
        return res;
    }
};
template <class S, S (*op)(S, S), S (*e)()>
struct segtree {
    int siz = 1;
    vector<S> dat;
    segtree(int n) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S> &a) {
        while (siz < a.size()) siz <<= 1;
        dat = vector<S>(siz << 1, e());
        for (int i = 0; i < a.size(); i++) dat[siz + i] = a[i];
        for (int i = siz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void set(int p, S x) {
        p += siz;
        dat[p] = x;
        while (p > 0) {
            p >>= 1;
            dat[p] = op(dat[2 * p], dat[2 * p + 1]);
        }
    }
    void add(int p, S x) { set(p, get(p) + x); }
    S get(int p) { return dat[p + siz]; }
    S prod(int l, int r) {
        S vl = e(), vr = e();
        l += siz, r += siz;
        while (l < r) {
            if (l & 1) vl = op(vl, dat[l++]);
            if (r & 1) vr = op(dat[--r], vr);
            l >>= 1, r >>= 1;
        }
        return op(vl, vr);
    }
    S all_prod() { return dat[1]; }
};

template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};
template <class T, T (*op)(T, T), T (*e)()>
struct sparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    sparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            for (int j = 0; j + (1 << i) <= (1 << len); j++) {
                table[i][j] = op(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
            }
        }
        logtable.resize(v.size() + 1);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        assert(l <= r);
        if (l == r) return e();
        int len = logtable[r - l];
        return op(table[len][l], table[len][r - (1 << len)]);
    }
};
template <class T, T (*op)(T, T), T (*e)()>
struct disjointsparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    disjointsparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len, e()));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            int shift = 1 << i;
            for (int j = 0; j < (int)v.size(); j += shift << 1) {
                int t = min(j + shift, (int)v.size());
                table[i][t - 1] = v[t - 1];
                for (int k = t - 2; k >= j; k--) table[i][k] = op(v[k], table[i][k + 1]);
                if (v.size() <= t) break;
                table[i][t] = v[t];
                int r = min(t + shift, (int)v.size());
                for (int k = t + 1; k < r; k++) table[i][k] = op(table[i][k - 1], v[k]);
            }
        }
        logtable.resize(1 << len);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        if (l == r) return e();
        if (l >= --r) return table[0][l];
        int len = logtable[l ^ r];
        return op(table[len][l], table[len][r]);
    };
};
struct lca_tree {
    int n, size;
    vector<vector<int>> par;
    vector<int> depth;
    lca_tree(vector<vector<int>> g, int root = 0) : n((int)g.size()), size(log2(n) + 2), par(size, vector<int>(n, -1)), depth(vector<int>(n, n)) {
        queue<int> que;
        depth[root] = 0;
        que.push(root);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            for (int i : g[p]) {
                if (depth[i] > depth[p] + 1) {
                    depth[i] = depth[p] + 1;
                    par[0][i] = p;
                    que.push(i);
                }
            }
        }
        for (int k = 0; k < size - 1; k++) {
            for (int i = 0; i < n; i++) {
                if (par[k][i] == -1)
                    par[k + 1][i] = -1;
                else
                    par[k + 1][i] = par[k][par[k][i]];
            }
        }
    }
    int query(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int k = size - 1; k >= 0; k--) {
            if (((depth[v] - depth[u]) >> k) & 1) v = par[k][v];
            if (u == v) return u;
        }
        for (int k = size - 1; k >= 0; k--) {
            if (par[k][u] != par[k][v]) {
                u = par[k][u];
                v = par[k][v];
            }
        }
        return par[0][u];
    }
    int dist(int u, int v) {
        int l = query(u, v);
        return depth[u] + depth[v] - 2 * depth[l];
    }
};
struct UnionFind {
    vector<int> par, siz, es;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        es.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
            es[i] = 0;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) {
            es[x]++;
            return false;
        }
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];
        es[x] += es[y] + 1;
        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
    int edges(int x) { return es[find(x)]; }
};
struct Mo {
    int n;
    vector<pair<int, int>> lr;

    explicit Mo(int n) : n(n) {}

    void add(int l, int r) { /* [l, r) */ lr.emplace_back(l, r); }

    template <typename AL, typename AR, typename EL, typename ER, typename O>
    void build(const AL &add_left, const AR &add_right, const EL &erase_left, const ER &erase_right, const O &out) {
        int q = (int)lr.size();
        int bs = n / min<int>(n, sqrt(q));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = lr[a].first / bs, bblock = lr[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? lr[a].second > lr[b].second : lr[a].second < lr[b].second;
        });
        int l = 0, r = 0;
        for (auto idx : ord) {
            while (l > lr[idx].first) add_left(--l);
            while (r < lr[idx].second) add_right(r++);
            while (l < lr[idx].first) erase_left(l++);
            while (r > lr[idx].second) erase_right(--r);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A &add, const E &erase, const O &out) {
        build(add, add, erase, erase, out);
    }
};
template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazy_segtree {
    int _n, sz = 1;
    vector<S> dat;
    vector<F> lazy;
    lazy_segtree(vector<S> a) : _n(int(a.size())) {
        while (sz < _n) sz <<= 1;
        dat.resize(sz * 2, e());
        lazy.resize(sz * 2, id());
        rep(i, _n) dat[sz + i] = a[i];
        for (int i = sz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void eval(int k) {
        dat[k] = mapping(lazy[k], dat[k]);
        if (k < sz) {
            lazy[k * 2] = composition(lazy[k], lazy[k * 2]);
            lazy[k * 2 + 1] = composition(lazy[k], lazy[k * 2 + 1]);
        }
        lazy[k] = id();
    }
    void apply(int a, int b, F f, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = composition(f, lazy[k]);
            eval(k);
            return;
        }
        int m = (l + r) >> 1;
        apply(a, b, f, 2 * k, l, m);
        apply(a, b, f, 2 * k + 1, m, r);
        dat[k] = op(dat[2 * k], dat[2 * k + 1]);
    }
    S prod(int a, int b, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return e();
        if (a <= l && r <= b) return dat[k];
        int m = (l + r) >> 1;
        S vl = prod(a, b, 2 * k, l, m);
        S vr = prod(a, b, 2 * k + 1, m, r);
        return op(vl, vr);
    }
};

template <class S, S (*op)(S, S), S (*e)()>
struct dual_segtree {
    int sz = 1, log = 0;
    vector<S> lz;
    dual_segtree(vector<S> a) {
        int n = a.size();
        while (sz < n) {
            sz <<= 1;
            log++;
        }
        lz.assign(sz << 1, e());
        for (int i = 0; i < n; i++) lz[i + sz] = a[i];
    }
    void push(int k) {
        int b = __builtin_ctz(k);
        for (int d = log; d > b; d--) {
            lz[k >> d << 1] = op(lz[k >> d << 1], lz[k >> d]);
            lz[k >> d << 1 | 1] = op(lz[k >> d << 1 | 1], lz[k >> d]);
            lz[k >> d] = e();
        }
    }
    void apply(int l, int r, S x) {
        l += sz, r += sz;
        push(l);
        push(r);
        while (l < r) {
            if (l & 1) {
                lz[l] = op(lz[l], x);
                l++;
            }
            if (r & 1) {
                r--;
                lz[r] = op(lz[r], x);
            }
            l >>= 1, r >>= 1;
        }
    }
    S get(int k) {
        k += sz;
        S res = e();
        while (k) {
            res = op(res, lz[k]);
            k >>= 1;
        }
        return res;
    }
};
ll modinv(int x, int modulo) {
    int a = x, b = modulo, u = 1, v = 0, t;
    while (b > 0) {
        t = a / b;
        swap(a -= t * b, b);
        swap(u -= t * v, v);
    }
    return (u >= 0 ? u % modulo : (modulo - (-u) % modulo) % modulo);
}
struct auxiliary_tree : lca_tree {
    vector<int> in;
    vector<vector<int>> G;
    auxiliary_tree(vector<vector<int>> &g) : lca_tree(g), in((int)g.size()), G((int)g.size()) {
        int t = 0;
        dfs(0, -1, t, g);
    }
    void dfs(int v, int p, int &t, vector<vector<int>> &g) {
        in[v] = t++;
        for (auto u : g[v]) {
            if (u != p) dfs(u, v, t, g);
        }
    }
    using lca_tree::depth;
    pair<int, vector<int>> query(vector<int> vs, bool decending = false) {
        // decending: only parent to child
        assert(!vs.empty());
        sort(vs.begin(), vs.end(), [&](int a, int b) { return in[a] < in[b]; });
        int m = vs.size();
        stack<int> st;
        st.push(vs[0]);
        for (int i = 0; i < m - 1; i++) {
            int w = lca_tree::query(vs[i], vs[i + 1]);
            if (w != vs[i]) {
                int l = st.top();
                st.pop();
                while (!st.empty() && depth[w] < depth[st.top()]) {
                    if (!decending) G[l].push_back(st.top());
                    G[st.top()].push_back(l);
                    l = st.top();
                    st.pop();
                }
                if (st.empty() || st.top() != w) {
                    st.push(w);
                    vs.push_back(w);
                }
                if (!decending) G[l].push_back(w);
                G[w].push_back(l);
            }
            st.push(vs[i + 1]);
        }
        while (st.size() > 1) {
            int x = st.top();
            st.pop();
            if (!decending) G[x].push_back(st.top());
            G[st.top()].push_back(x);
        }
        // {root,vertex_list}
        return make_pair(st.top(), vs);
    }
    void clear(vector<int> vs) {
        for (int v : vs) G[v].clear();
    }
};
struct LowLink {
    vector<vector<int>> g;
    vector<int> ord, low, out;
    vector<bool> used;
    vector<pair<int, int>> bridge;
    vector<pair<int, int>> articulation;
    int unions;
    LowLink(vector<vector<int>> g) : g(g) {
        int n = (int)g.size();
        ord.resize(n);
        low.resize(n);
        out.resize(n);
        used.resize(n);
        unions = 0;
        int t = 0;
        for (int i = 0; i < n; i++) {
            if (!used[i]) {
                dfs(i, t, -1);
                unions++;
            }
        }
    }
    void dfs(int v, int &t, int par) {
        used[v] = true;
        ord[v] = t++, low[v] = ord[v];
        int cnt = 0;
        bool par_back = false;
        for (int to : g[v]) {
            if (!used[to]) {
                dfs(to, t, v);
                low[v] = min(low[v], low[to]);
                if (ord[v] < low[to]) bridge.push_back(minmax(v, to));
                if (ord[v] <= low[to]) cnt++;
            } else if (to != par || par_back) {
                low[v] = min(low[v], ord[to]);
            } else
                par_back = true;
        }
        if (par != -1) cnt++;
        if (cnt >= 2) articulation.push_back({v, cnt});
        out[v] = t;
    }
};
void solve(string s){
    int n=s.size();
    vector<int>v{0};
    rep(i,n){
        if(s[i]=='('){
            if(v.size()%2==1)v.back()++;
            else v.push_back(1);
        }
        else{
            if(v.size()%2==0)v.back()++;
            else v.push_back(1);
        }
    }
    if(v.size()%2==1)v.push_back(0);
    stack<int>mi,ma;
    int ans=0;
    rep(i,v.size()/2){
        int a=v[2*i],b=v[2*i+1];
        //minimum:(b+1)/2 maximum:2*b
        //digest b
        mi.push(a),ma.push(a);
        while(ma.size()&&b){
            int k=ma.top();
            ma.pop();
            if(k>(b+1)/2){
                k-=(b+1)/2;
                b=0;
                ma.push(k);
                break;
            }
            b-=2*k;
        }
        if(b){
            ans+=(b+1)/2;
            while(ma.size())ma.pop();
            while(mi.size())mi.pop();
            continue;
        }
        //ma:survived
        b=v[2*i+1];
        while(mi.size()&&b){
            int k=mi.top();
            mi.pop();
            if(k>2*b){
                k-=2*b;
                mi.push(k);
                break;
            }
            b-=(k+1)/2;
        }
    }
    while(!mi.empty()){
        int k=mi.top();
        mi.pop();
        ans+=(k+1)/2;
    }
    cout<<ans<<endl;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n,m,k,d,b;
    string s;
    while(cin>>s){
        if(s=="#")break;
    solve(s);
    }
}
accuracy: 1
time_ms: 10
memory_kb: 5344
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
#define rrep(i,start,end) for (long long i = start;i >= (long long)(end);i--)
#define repn(i,end) for(long long i = 0; i <= (long long)(end); i++)
#define reps(i,start,end) for(long long i = start; i < (long long)(end); i++)
#define repsn(i,start,end) for(long long i = start; i <= (long long)(end); i++)
#define each(p,a) for(auto &p:a)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<long long> vll;
typedef vector<pair<long long ,long long>> vpll;
typedef vector<vector<long long>> vvll;
typedef set<ll> sll;
typedef map<long long , long long> mpll;
typedef pair<long long ,long long> pll;
typedef tuple<long long , long long , long long> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (int)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
inline ll lfloor(ll x,ll m){return (x - ((x % m+ m)%m))/m;}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

// for AOJ or ICPC or etc..
// 全部が0だったらtrueを返す
template<class Tp> bool zero (const Tp &x) {return x == 0;}
template<class Tp, class... Args> bool zero (const Tp &x, const Args& ...args) {return zero(x) and zero(args...);}


// 変数をちゃんと全部受け取る！
void solve(string s){
  vector<pair<char,ll>> rle;
  ll n  = s.size();
  rep(i,n){
    if(rle.empty() or rle.back().first != s[i]){
      rle.push_back({s[i],1});
    }else{
      rle.back().second++;
    }
  }
  
  ll ans = 0;
  {
    ll now = 0;ll mi = 0;
    each(p,rle){
      if(p.first == '('){
        now += p.second;
      }else{
        now -= (p.second+1)/2;
      }
      chmin(mi,now);
    }
    ans += -mi;
  }
  {
    ll now = (ans+1)/2;
    each(p,rle){
      if(p.first == '('){
        now += (p.second+1)/2;
      }else{
        now -= p.second;
      }
      chmax(now,0LL);
    }
    if(now > 0){
      ans += now;
    }
  }
  cout << ans << endl;

}
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  while(true){
    Str(s);
    if(s == "#")break;
    solve(s);
  }
}
accuracy: 1
time_ms: 10
memory_kb: 11184
final_rank: 17

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>

#ifdef DEFINED_ONLY_IN_LOCAL
#include "cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

const long long INF = 1e9;
// const long long MOD = 1e9 + 7;
const long long MOD = 998244353;
const long long LINF = 1e18;
using namespace std;
// using namespace atcoder;

#define YES(n) cout << ((n) ? "YES" : "NO") << endl
#define Yes(n) cout << ((n) ? "Yes" : "No") << endl
#define POSSIBLE(n) cout << ((n) ? "POSSIBLE" : "IMPOSSIBLE") << endl
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << endl
#define Takahashi(n) cout << ((n) ? "Takahashi" : "Aoki") << endl
#define TAKAHASHI(n) cout << ((n) ? "TAKAHASHI" : "AOKI") << endl
#define First(n) cout << ((n) ? "First" : "Second") << endl
#define FIRST(n) cout << ((n) ? "FIRST" : "SECOND") << endl
#define COUT(x) cout << (x) << endl
#define SCOUT(x) cout << (x) << " "
#define VECCOUT(x)                                  \
    for (auto &youso_ : (x))                        \
        cout << right << setw(3) << youso_ << " "; \
    cout << endl
#define ENDL cout << endl
#define CIN(...)     \
    int __VA_ARGS__; \
    CINT(__VA_ARGS__)
#define LCIN(...)          \
    long long __VA_ARGS__; \
    CINT(__VA_ARGS__)
#define SCIN(...)       \
    string __VA_ARGS__; \
    CINT(__VA_ARGS__)
#define VECCIN(x)            \
    for (auto &youso_ : (x)) \
    cin >> youso_
#define mp make_pair

typedef long long ll;
typedef vector<long long> vl;
typedef vector<vl> vvl;
typedef pair<long long, long long> pll;

#define COUT(x) cout << (x) << endl
void CINT()
{
}
template <class Head, class... Tail>
void CINT(Head &&head, Tail &&...tail)
{
    cin >> head;
    CINT(move(tail)...);
}

// using mint = modint998244353;
// ostream& operator<< (ostream& os, const mint &x) {os << x.val(); return os;}

void Main()
{
    while (true)
    {
        SCIN(S);
        if (S == "#")
            break;
        int rem_min = 0, rem_max = 0, ans = 0;
        vl ans_v,rem_min_v,
            rem_max_v;
        for (size_t i = 0; i < S.size(); i++)
        {

            if (i + 1 < S.size() && S.at(i) == S.at(i + 1))
            {
                if (S.at(i) == '(')
                {
                    rem_min += 1;
                    rem_max += 2;
                }
                else
                {
                    if (rem_max == 0)
                    {
                        ans += 1;
                    }
                    else
                    {
                        rem_min = max(0, rem_min - 2);
                        rem_max = max(0, rem_max - 1);
                    }
                }
                i++;
                ans_v.push_back(ans);
                rem_min_v.push_back(rem_min);
                rem_max_v.push_back(rem_max);
            }
            else
            {
                if (S.at(i) == '(')
                {
                    rem_min += 1;
                    rem_max += 1;
                }
                else
                {
                    if (rem_max == 0)
                    {
                        ans += 1;
                    }
                    else
                    {
                        rem_min = max(0, rem_min - 1);
                        rem_max = max(0, rem_max - 1);
                    }
                }
            }
                ans_v.push_back(ans);
                rem_min_v.push_back(rem_min);
                rem_max_v.push_back(rem_max);
        }
        ans += (rem_min + 1) -1;
        // VECCOUT(ans_v);
        // VECCOUT(rem_min_v);
        // VECCOUT(rem_max_v);
        // VECCOUT(S);
        COUT(ans);
    }
}

int main()
{
    cout << fixed << setprecision(15);
    Main();
    return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 10720
final_rank: 20

code_snippet: #include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <forward_list>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#ifdef RUTHEN_LOCAL
#include <debug.hpp>
#else
#define show(x) true
#endif

// type definition
using i64 = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using f32 = float;
using f64 = double;
using f128 = long double;
template <class T> using pque = std::priority_queue<T>;
template <class T> using pqueg = std::priority_queue<T, std::vector<T>, std::greater<T>>;
// overload
#define overload4(_1, _2, _3, _4, name, ...) name
#define overload3(_1, _2, _3, name, ...) name
#define overload2(_1, _2, name, ...) name
// for loop
#define REP1(a) for (long long _ = 0; _ < (a); _++)
#define REP2(i, a) for (long long i = 0; i < (a); i++)
#define REP3(i, a, b) for (long long i = (a); i < (b); i++)
#define REP4(i, a, b, c) for (long long i = (a); i < (b); i += (c))
#define REP(...) overload4(__VA_ARGS__, REP4, REP3, REP2, REP1)(__VA_ARGS__)
#define RREP1(a) for (long long _ = (a)-1; _ >= 0; _--)
#define RREP2(i, a) for (long long i = (a)-1; i >= 0; i--)
#define RREP3(i, a, b) for (long long i = (b)-1; i >= (a); i--)
#define RREP(...) overload3(__VA_ARGS__, RREP3, RREP2, RREP1)(__VA_ARGS__)
#define FORE1(x, a) for (auto&& x : a)
#define FORE2(x, y, a) for (auto&& [x, y] : a)
#define FORE3(x, y, z, a) for (auto&& [x, y, z] : a)
#define FORE(...) overload4(__VA_ARGS__, FORE3, FORE2, FORE1)(__VA_ARGS__)
#define FORSUB(t, s) for (long long t = (s); t >= 0; t = (t == 0 ? -1 : (t - 1) & (s)))
// function
#define ALL(a) (a).begin(), (a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define SORT(a) std::sort((a).begin(), (a).end())
#define RSORT(a) std::sort((a).rbegin(), (a).rend())
#define REV(a) std::reverse((a).begin(), (a).end())
#define UNIQUE(a)                      \
    std::sort((a).begin(), (a).end()); \
    (a).erase(std::unique((a).begin(), (a).end()), (a).end())
#define LEN(a) (int)((a).size())
#define MIN(a) *std::min_element((a).begin(), (a).end())
#define MAX(a) *std::max_element((a).begin(), (a).end())
#define SUM1(a) std::accumulate((a).begin(), (a).end(), 0LL)
#define SUM2(a, x) std::accumulate((a).begin(), (a).end(), (x))
#define SUM(...) overload2(__VA_ARGS__, SUM2, SUM1)(__VA_ARGS__)
#define LB(a, x) std::distance((a).begin(), std::lower_bound((a).begin(), (a).end(), (x)))
#define UB(a, x) std::distance((a).begin(), std::upper_bound((a).begin(), (a).end(), (x)))
template <class T, class U> inline bool chmin(T& a, const U& b) { return (a > T(b) ? a = b, 1 : 0); }
template <class T, class U> inline bool chmax(T& a, const U& b) { return (a < T(b) ? a = b, 1 : 0); }
template <class T, class S> inline T floor(const T x, const S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T, class S> inline T ceil(const T x, const S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}
template <class T, class S> std::pair<T, T> inline divmod(const T x, const S y) {
    T q = floor(x, y);
    return {q, x - q * y};
}
// 10 ^ n
constexpr long long TEN(int n) { return (n == 0) ? 1 : 10LL * TEN(n - 1); }
// 1 + 2 + ... + n
#define TRI1(n) ((n) * ((n) + 1LL) / 2)
// l + (l + 1) + ... + r
#define TRI2(l, r) (((l) + (r)) * ((r) - (l) + 1LL) / 2)
#define TRI(...) overload2(__VA_ARGS__, TRI2, TRI1)(__VA_ARGS__)
// bit operation
// bit[i] (= 0 or 1)
#define IBIT(bit, i) (((bit) >> (i)) & 1)
// (0, 1, 2, 3, 4) -> (0, 1, 3, 7, 15)
#define MASK(n) ((1LL << (n)) - 1)
#define POW2(n) (1LL << (n))
// (0, 1, 2, 3, 4) -> (0, 1, 1, 2, 1)
int popcnt(int x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 1, 2)
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(u32 x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(i64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int topbit(u64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 0, 2)
int lowbit(int x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(u32 x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(i64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
int lowbit(u64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
// binary search
template <class T, class F> T bin_search(T ok, T ng, F& f) {
    while ((ok > ng ? ok - ng : ng - ok) > 1) {
        T md = (ng + ok) >> 1;
        (f(md) ? ok : ng) = md;
    }
    return ok;
}
template <class T, class F> T bin_search_real(T ok, T ng, F& f, const int iter = 100) {
    for (int _ = 0; _ < iter; _++) {
        T md = (ng + ok) / 2;
        (f(md) ? ok : ng) = md;
    }
    return ok;
}
// rotate matrix counterclockwise by pi / 2
template <class T> void rot(std::vector<std::vector<T>>& a) {
    if ((int)(a.size()) == 0) return;
    if ((int)(a[0].size()) == 0) return;
    int n = (int)(a.size()), m = (int)(a[0].size());
    std::vector res(m, std::vector<T>(n));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            res[m - 1 - j][i] = a[i][j];
        }
    }
    a.swap(res);
}
// const value
constexpr int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
constexpr int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
// infinity
template <class T> constexpr T INF = 0;
template <> constexpr int INF<int> = 1'000'000'000;                 // 1e9
template <> constexpr i64 INF<i64> = i64(INF<int>) * INF<int> * 2;  // 2e18
template <> constexpr u32 INF<u32> = INF<int>;                      // 1e9
template <> constexpr u64 INF<u64> = INF<i64>;                      // 2e18
template <> constexpr f32 INF<f32> = INF<i64>;                      // 2e18
template <> constexpr f64 INF<f64> = INF<i64>;                      // 2e18
template <> constexpr f128 INF<f128> = INF<i64>;                    // 2e18
// I/O
// input
template <class T> std::istream& operator>>(std::istream& is, std::vector<T>& v) {
    for (auto&& i : v) is >> i;
    return is;
}
template <class... T> void in(T&... a) { (std::cin >> ... >> a); }
void scan() {}
template <class Head, class... Tail> void scan(Head& head, Tail&... tail) {
    in(head);
    scan(tail...);
}
// input macro
#define INT(...)     \
    int __VA_ARGS__; \
    scan(__VA_ARGS__)
#define I64(...)     \
    i64 __VA_ARGS__; \
    scan(__VA_ARGS__)
#define U32(...)     \
    u32 __VA_ARGS__; \
    scan(__VA_ARGS__)
#define U64(...)     \
    u64 __VA_ARGS__; \
    scan(__VA_ARGS__)
#define F32(...)     \
    f32 __VA_ARGS__; \
    scan(__VA_ARGS__)
#define F64(...)     \
    f64 __VA_ARGS__; \
    scan(__VA_ARGS__)
#define F128(...)     \
    f128 __VA_ARGS__; \
    scan(__VA_ARGS__)
#define STR(...)             \
    std::string __VA_ARGS__; \
    scan(__VA_ARGS__)
#define CHR(...)      \
    char __VA_ARGS__; \
    scan(__VA_ARGS__)
#define VEC(type, name, size)     \
    std::vector<type> name(size); \
    scan(name)
#define VEC2(type, name1, name2, size)          \
    std::vector<type> name1(size), name2(size); \
    for (int i = 0; i < size; i++) scan(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                \
    std::vector<type> name1(size), name2(size), name3(size); \
    for (int i = 0; i < size; i++) scan(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                      \
    std::vector<type> name1(size), name2(size), name3(size), name4(size); \
    for (int i = 0; i < size; i++) scan(name1[i], name2[i], name3[i], name4[i])
#define VV(type, name, h, w)                       \
    std::vector name((h), std::vector<type>((w))); \
    scan(name)
// output
template <class T> std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
    auto n = v.size();
    for (size_t i = 0; i < n; i++) {
        if (i) os << ' ';
        os << v[i];
    }
    return os;
}
template <class... T> void out(const T&... a) { (std::cout << ... << a); }
void print() { out('\n'); }
template <class Head, class... Tail> void print(Head&& head, Tail&&... tail) {
    out(head);
    if (sizeof...(Tail)) out(' ');
    print(tail...);
}
// for interactive problems
void printi() { std::cout << std::endl; }
template <class Head, class... Tail> void printi(Head&& head, Tail&&... tail) {
    out(head);
    if (sizeof...(Tail)) out(' ');
    printi(tail...);
}
// bool output
void YES(bool t = 1) { print(t ? "YES" : "NO"); }
void Yes(bool t = 1) { print(t ? "Yes" : "No"); }
void yes(bool t = 1) { print(t ? "yes" : "no"); }
void NO(bool t = 1) { YES(!t); }
void No(bool t = 1) { Yes(!t); }
void no(bool t = 1) { yes(!t); }
void POSSIBLE(bool t = 1) { print(t ? "POSSIBLE" : "IMPOSSIBLE"); }
void Possible(bool t = 1) { print(t ? "Possible" : "Impossible"); }
void possible(bool t = 1) { print(t ? "possible" : "impossible"); }
void IMPOSSIBLE(bool t = 1) { POSSIBLE(!t); }
void Impossible(bool t = 1) { Possible(!t); }
void impossible(bool t = 1) { possible(!t); }
void FIRST(bool t = 1) { print(t ? "FIRST" : "SECOND"); }
void First(bool t = 1) { print(t ? "First" : "Second"); }
void first(bool t = 1) { print(t ? "first" : "second"); }
void SECOND(bool t = 1) { FIRST(!t); }
void Second(bool t = 1) { First(!t); }
void second(bool t = 1) { first(!t); }
// I/O speed up
struct SetUpIO {
    SetUpIO() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout << std::fixed << std::setprecision(15);
    }
} set_up_io;
// #include "data_structure/unionfind.hpp"
using namespace std;

void solve(string S) {
    const int N = LEN(S);
    int ans = 0;
    REP(2) {
        vector<int> stk;
        REP(i, N) {
            if (S[i] == '(') {
                stk.push_back(i);
            } else {
                int M = LEN(stk);
                if (M >= 2 and stk[M - 2] + 1 == stk[M - 1]) {
                    stk.pop_back();
                    stk.pop_back();
                } else if (M >= 1) {
                    stk.pop_back();
                }
            }
        }
        while (LEN(stk)) {
            int M = LEN(stk);
            ans++;
            if (M >= 2 and stk[M - 2] + 1 == stk[M - 1]) {
                stk.pop_back();
                stk.pop_back();
            } else if (M >= 1) {
                stk.pop_back();
            }
        }
        REV(S);
        REP(i, N) {
            if (S[i] == '(') {
                S[i] = ')';
            } else {
                S[i] = '(';
            }
        }
    }
    print(ans);
    return;
}

int main() {
    string S;
    while (cin >> S, S != "#") solve(S);
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 5412
final_rank: 8