#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <algorithm>
#include <string>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <math.h>
#define M_PI    3.14159265358979323846  /* pi */
#define ri(i) int i;scanf("%d",&i);
#define rii(i,j) int i,j;scanf("%d%d",&i,&j);
#define rc(i) char i;cin>>i;
#define rll(i) long long i;cin>>i;
#define ff(i,s,n) for(int i=(s);i<(n);i++)
#define fr(i,s,n) for(int i=(n-1);i>=(s);i--)
#define FF(i,s,n) for(int i=(s);i<=(n);i++)
#define Fr(i,s,n) for(int i=(n);i>=(s);i--)
#define mp(a,b) make_pair(a,b)

template<typename T, typename U> inline void swap(T &a, U &b) {
    a = a^b;
    b = a^b;
    a = a^b;
}

inline void swap(int &a, int &b) {
    a = a^b;
    b = a^b;
    a = a^b;
}

inline void swap(long long &a, long long &b) {
    a = a^b;
    b = a^b;
    a = a^b;
}

template<typename T, typename U> inline void smax(T &a, U b) {
    if (b > a)a = b;
}

template<typename T, typename U> inline void smin(T &a, U b) {
    if (b < a)a = b;
}

inline int gcd(int a, int b) {
    if (a < b)swap(a, b);
    while (b > 0) {
        a %= b;
        swap(a, b);
    }
    return a;
}

long long nchose(int a, int b) {
    long long ans = 1;
    smax(a, b - a);
    int p = 2;

    FF(i, b - a + 1, b) {
        ans *= (long long) i;
        while (p <= a && ans % p == 0)ans /= p++;
    }
    return ans;
}

using namespace std;
static int MOD = 1073741824;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<vi, vi> pvi;
typedef vector<vi> vvi;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<pair<string, string> > vpss;
typedef vector<pii > vpii;
typedef vector<pll > vpll;
typedef vector<vpii > vvpii;
typedef map<int, int> mii;
typedef unordered_map<int, int> imap;
typedef unordered_map<ll, ll> lmap;

const int tw=1<<20;
int n,m;
int l[2*tw],r[2*tw],tot[2*tw];
string s;

int main() {
    cin>>s;n=s.length();
    ff(i,0,n){
        int p=i+tw;
        if(s[i]=='(')l[p]++;
        else if(s[i]==')')r[p]++;
    }
    fr(i,2,tw+n){
        int p=i/2;
        if(i%2){
            int temp=min(l[p],r[i]);
            tot[p]+=temp+tot[i];
            l[p]+=l[i]-temp;
            r[p]+=r[i]-temp;
        }else{
            int temp=min(l[i],r[p]);
            tot[p]+=temp+tot[i];
            l[p]+=l[i]-temp;
            r[p]+=r[i]-temp;
        }
    }
    cin>>m;
    ff(i,0,m){
        rii(x,y);
        x--;y--;
        x+=tw;y+=tw;
        if(x==y){cout<<0<<endl;continue;}
        int xl=l[x],xr=r[x],xtot=tot[x],yl=l[y],yr=r[y],ytot=tot[y];
        while(x/2!=y/2){
            if(x%2==0){
                int t=x+1;
                int temp=min(xl,r[t]);
                xtot+=temp+tot[t];
                xl+=l[t]-temp;
                xr+=r[t]-temp;
            }
            x/=2;
            if(y%2==1){
                int t=y-1;
                int temp=min(yr,l[t]);
                ytot+=temp+tot[t];
                yl+=l[t]-temp;
                yr+=r[t]-temp;
            }
            y/=2;
        }
        int ans=(xtot+ytot+min(xl,yr))*2;
        cout<<ans<<endl;
    }
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1000005;
char S[maxn];
int n;
struct SegTree {
	struct Node {
		int l,r;
		int maxlen, open, close;
	}v[maxn<<2];
	inline int ll(int x)		{return x<<1;}
	inline int rr(int x)		{return x<<1|1;}
	inline int mm(int x)		{return (v[x].l+v[x].r)>>1;}
	void pushup(int x) {
		// printf("[%d %d] -> [%d %d %d] and [%d %d %d]\n", v[x].l, v[x].r, v[ll(x)].maxlen, v[ll(x)].open, v[ll(x)].close, v[rr(x)].maxlen, v[rr(x)].open, v[rr(x)].close);
		int t=min(v[ll(x)].open, v[rr(x)].close);
		v[x].maxlen=v[ll(x)].maxlen+v[rr(x)].maxlen+t;
		v[x].open=v[ll(x)].open+v[rr(x)].open-t;
		v[x].close=v[ll(x)].close+v[rr(x)].close-t;
		// printf("%d %d %d\n", v[x].maxlen,v[x].open,v[x].close);
	}
	void build(int L,int R,int x=1) {
		v[x].l=L,v[x].r=R,v[x].open=v[x].close=v[x].maxlen=0;
		if(L==R) {
			if(S[L]=='(')	v[x].open=1;
			if(S[L]==')')	v[x].close=1;
			return;
		}
		int m=mm(x);
		build(L,m,ll(x)), build(m+1,R,rr(x));
		pushup(x);
	}
	Node combine(const Node &a, const Node &b) {
		int t=min(a.open, b.close);
		int maxlen=a.maxlen+b.maxlen+t;
		int open=a.open+b.open-t;
		int close=a.close+b.close-t;
		return (Node){-1,-1,maxlen,open,close};
	}
	Node query(int L,int R,int x=1) {
		if(L<=v[x].l & v[x].r<=R) {
			return v[x];
		}
		int m=mm(x);
		if(R <= m)		return query(L,R,ll(x));
		if(L >= m+1)	return query(L,R,rr(x));
		return combine(query(L,R, ll(x)), query(L,R,rr(x)));
	}
	int ask(int L,int R) {
		return query(L,R).maxlen<<1;
	}
}tr;
int main(int argc, char const *argv[]) {
#ifndef ONLINE_JUDGE
    freopen("C.in", "r", stdin);
    // freopen("out", "w", stdout);
#endif
    // ios::sync_with_stdio(false);		cin.tie(0);
    scanf("%s",S+1);
    n=strlen(S+1);
    tr.build(1,n);
    // DEBUG(tr.v[1].maxlen);
    int Q;	scanf("%d", &Q);
    while(Q--) {
    	int l,r;	scanf("%d%d", &l,&r);
    	printf("%d\n", tr.ask(l,r));
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
char S[1000005];
int P[1000005],SIZE,CUR,ans[1000005];
struct QNode {
	int l,r,lb,id;
	friend bool operator<(const QNode &x,const QNode &y) {
		return MP(x.lb,x.r) < MP(y.lb,y.r);
	}
	bool isSmall() {
		return r-l+1<=SIZE;
	}
}qq[100005];
int R1,R2,vis[1000005], temp_vis[1000005];
bool copied[1000005];
vector<int> copylist;
void init() {
	CLR(vis,-1);
	CLR(copied,0);
	R1=R2=0;
	copylist.clear();
}
void reset() {
	for(auto i : copylist)	copied[i]=0;
	copylist.clear(),R2=0;
}
int get(int x) {
	return copied[x] ? temp_vis[x] : vis[x];
}
int ask(int L,int R) {
	FOR(i,L,R) if(~P[i]) {
		if(get(P[i])==CUR) {
			++R2;
		}
		copylist.push_back(i);		copied[i]=1;
		temp_vis[i]=CUR;
	}
	return R2;
}
int main(int argc, char const *argv[]) {
	#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	// freopen("C.out","w",stdout);
	#endif
	CLR(P,-1);
	scanf("%s", S+1);
	int n = strlen(S+1);
	stack<pair<char,int> > st;
	FOR(i,1,n) {
		if(S[i]==')') {
			if(!st.empty() && st.top().first == '(') {
				int a=st.top().second, b=i;
				P[a]=b,P[b]=a;
				st.pop();
			}
		}else
			st.push(MP('(',i));
	}
	for(SIZE=1;SIZE*SIZE<=n;++SIZE);
	init();
	int Q;	scanf("%d",&Q);
	rep(i,Q) {
		int l,r;	scanf("%d%d",&l,&r);
		qq[i] = (QNode){l,r,l/SIZE,i};
		if(qq[i].isSmall()) {
			ans[qq[i].id] = ask(qq[i].l,qq[i].r);
			reset();
		}
	}
	sort(qq,qq+Q);
	int preb=-1,nowr;
	rep(i,Q) {
		if(qq[i].isSmall())	continue;
		int l=qq[i].l,r=qq[i].r,lb=qq[i].lb, &res=ans[qq[i].id];
		res=0;
		// printf("[%d %d]\n",l,r);
		if(lb!=preb) {
			CUR=i;
			init();
			FOR(k,(lb+1)*SIZE,r) {
				if(~P[k]) {
					if(vis[P[k]] == i)
						++R1;
					vis[k]=i;
				}
			}
			nowr=r;
		}
		FOR(k,nowr+1,r) {
			if(~P[k]) {
				// printf("%d <-> %d  %d\n",k,P[k], vis[P[k]]==CUR);
				if(vis[P[k]] == CUR)
					++R1;
				vis[k]=i;
			}
		}
		nowr=r;
		R2=0;
		// printf("!! %d %d\n",l,(lb+1)*SIZE-1);
		ask(l, (lb+1)*SIZE-1);
		// printf("r1=%d r2=%d res=%d\n",R1,R2,res);
		res=R1+R2;
		preb=lb;
		reset();
	}
	rep(i,Q)
		printf("%d\n",ans[i]+ans[i]);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
char S[1000005];
int P[1000005],SIZE,CUR,ans[1000005];
struct QNode {
	int l,r,lb,id;
	friend bool operator<(const QNode &x,const QNode &y) {
		return MP(x.lb,x.r) < MP(y.lb,y.r);
	}
	bool isSmall() {
		return r-l+1<=SIZE;
	}
}qq[100005];
int R1,R2,vis[1000005], temp_vis[1000005];
bool copied[1000005];
vector<int> copylist;
void init() {
	CLR(vis,-1);
	CLR(copied,0);
	R1=R2=0;
	copylist.clear();
}
void reset() {
	TR(i,copylist) {
		copied[*i]=0;
	}
	copylist.clear(),R2=0;
}
int get(int x) {
	return copied[x] ? temp_vis[x] : vis[x];
}
int ask(int L,int R) {
	FOR(i,L,R) if(~P[i]) {
		if(get(P[i])==CUR) {
			++R2;
		}
		copylist.push_back(i);		copied[i]=1;
		temp_vis[i]=CUR;
	}
	return R2;
}
int main(int argc, char const *argv[]) {
	#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	// freopen("C.out","w",stdout);
	#endif
	CLR(P,-1);
	scanf("%s", S+1);
	int n = strlen(S+1);
	stack<pair<char,int> > st;
	FOR(i,1,n) {
		if(S[i]==')') {
			if(!st.empty() && st.top().first == '(') {
				int a=st.top().second, b=i;
				P[a]=b,P[b]=a;
				st.pop();
			}
		}else
			st.push(MP('(',i));
	}
	for(SIZE=1;SIZE*SIZE<=n;++SIZE);
	init();
	int Q;	scanf("%d",&Q);
	rep(i,Q) {
		int l,r;	scanf("%d%d",&l,&r);
		qq[i] = (QNode){l,r,l/SIZE,i};
		if(qq[i].isSmall()) {
			ans[qq[i].id] = ask(qq[i].l,qq[i].r);
			reset();
		}
	}
	sort(qq,qq+Q);
	int preb=-1,nowr;
	rep(i,Q) {
		if(qq[i].isSmall())	continue;
		int l=qq[i].l,r=qq[i].r,lb=qq[i].lb, &res=ans[qq[i].id];
		res=0;
		// printf("[%d %d]\n",l,r);
		if(lb!=preb) {
			CUR=i;
			init();
			FOR(k,(lb+1)*SIZE,r) {
				if(~P[k]) {
					if(vis[P[k]] == i)
						++R1;
					vis[k]=i;
				}
			}
			nowr=r;
		}
		FOR(k,nowr+1,r) {
			if(~P[k]) {
				// printf("%d <-> %d  %d %d\n",k,P[k], vis[P[k]],CUR);
				if(vis[P[k]] == CUR)
					++R1;
				vis[k]=CUR;
			}
		}
		nowr=r;
		R2=0;
		ask(l, (lb+1)*SIZE-1);
		// printf("r1=%d r2=%d res=%d\n",R1,R2,res);
		res=R1+R2;
		preb=lb;
		reset();
	}
	rep(i,Q)
		printf("%d\n",ans[i]+ans[i]);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1000005;
char S[maxn];
vector<int> L[maxn];
struct QNode {
	int l,r,id;
	bool operator<(const QNode &rhs) const {
		return r < rhs.r;
	}
	void read(int id) {
		scanf("%d%d", &l,&r);	this->id=id;
	}
}qq[100005];
int s[maxn], ans[100005];
inline int getsum(int x) {
	int res=0;
	for(;x;x-=x&-x)
		res+=s[x];
	return res;
}
int main(int argc, char const *argv[]) {
#ifndef ONLINE_JUDGE
    freopen("C.in", "r", stdin);
    // freopen("out", "w", stdout);
#endif
    // ios::sync_with_stdio(false);		cin.tie(0);
    scanf("%s", S+1);
    int n=strlen(S+1);
    stack<pair<char, int> > st;
    FOR(i,1,n) {
    	if(S[i]==')') {
    		if(!st.empty() && st.top().first == '(')	{
    			L[i].push_back(st.top().second);
    			st.pop();
    		}
    	}else
    		st.push(MP(S[i], i));
    }
    int Q;	scanf("%d", &Q);
    rep(i,Q)	qq[i].read(i);
    sort(qq, qq+Q);
    int s1=0, nowq=0;
    FOR(i,1,n) {
    	for(auto x : L[i]) {
    		for(; x<=n; x+=x&-x)
    			++s[x];
    		++s1;
    	}
    	while(nowq<Q && qq[nowq].r == i) {
    		ans[qq[nowq].id] = s1-getsum(qq[nowq].l-1), ++nowq;
    	}
    }
    rep(i,Q)
    	printf("%d\n", ans[i]<<1);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
char S[1000005];
int P[1000005],SIZE,CUR,ans[1000005];
struct QNode {
	int l,r,lb,id;
	friend bool operator<(const QNode &x,const QNode &y) {
		return MP(x.lb,x.r) < MP(y.lb,y.r);
	}
	bool isSmall() {
		return r-l+1<=SIZE;
	}
}qq[100005];
int R1,R2,vis[1000005], temp_vis[1000005];
bool copied[1000005];
vector<int> copylist;
void init() {
	TR(i,copylist)
		copied[*i]=0;
	R1=R2=0;
	copylist.clear();
}
void reset() {
	TR(i,copylist) {
		copied[*i]=0;
	}
	copylist.clear(),R2=0;
}
int get(int x) {
	return copied[x] ? temp_vis[x] : vis[x];
}
int ask(int L,int R) {
	FOR(i,L,R) if(~P[i]) {
		if(get(P[i])==CUR) {
			++R2;
		}
		copylist.push_back(i);		copied[i]=1;
		temp_vis[i]=CUR;
	}
	return R2;
}
int main(int argc, char const *argv[]) {
	#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	// freopen("C.out","w",stdout);
	#endif
	CLR(P,-1);
	scanf("%s", S+1);
	int n = strlen(S+1);
	stack<pair<char,int> > st;
	FOR(i,1,n) {
		if(S[i]==')') {
			if(!st.empty() && st.top().first == '(') {
				int a=st.top().second, b=i;
				P[a]=b,P[b]=a;
				st.pop();
			}
		}else
			st.push(MP('(',i));
	}
	for(SIZE=1;SIZE*SIZE<=n;++SIZE);
	init();
	int Q;	scanf("%d",&Q);
	rep(i,Q) {
		int l,r;	scanf("%d%d",&l,&r);
		qq[i] = (QNode){l,r,l/SIZE,i};
		if(qq[i].isSmall()) {
			ans[qq[i].id] = ask(qq[i].l,qq[i].r);
			reset();
		}
	}
	sort(qq,qq+Q);
	int preb=-1,nowr;
	rep(i,Q) {
		if(qq[i].isSmall())	continue;
		int l=qq[i].l,r=qq[i].r,lb=qq[i].lb, &res=ans[qq[i].id];
		res=0;
		// printf("[%d %d]\n",l,r);
		if(lb!=preb) {
			CUR=i+1;
			init();
			FOR(k,(lb+1)*SIZE,r) {
				if(~P[k]) {
					if(vis[P[k]] == i)
						++R1;
					vis[k]=i;
				}
			}
			nowr=r;
		}
		FOR(k,nowr+1,r) {
			if(~P[k]) {
				if(vis[P[k]] == CUR)
					++R1;
				vis[k]=CUR;
			}
		}
		nowr=r;
		R2=0;
		ask(l, (lb+1)*SIZE-1);
		res=R1+R2;
		preb=lb;
		reset();
	}
	rep(i,Q)
		printf("%d\n",ans[i]+ans[i]);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 1000005;
char S[maxn];
vector<int> L[maxn];
struct QNode {
	int l,r,id;
	bool operator<(const QNode &rhs) const {
		return r < rhs.r;
	}
	void read(int id) {
		scanf("%d%d", &l,&r);	this->id=id;
	}
}qq[100005];
int s[maxn], ans[100005];
inline int getsum(int x) {
	int res=0;
	for(;x;x-=x&-x)
		res+=s[x];
	return res;
}
int main(int argc, char const *argv[]) {
#ifndef ONLINE_JUDGE
    freopen("C.in", "r", stdin);
    // freopen("out", "w", stdout);
#endif
    // ios::sync_with_stdio(false);		cin.tie(0);
    scanf("%s", S+1);
    int n=strlen(S+1);
    stack<pair<char, int> > st;
    FOR(i,1,n) {
    	if(S[i]==')') {
    		while(!st.empty() && st.top().first == '(')	{
    			L[i].push_back(st.top().second);
    			st.pop();
    		}
    	}else
    		st.push(MP(S[i], i));
    }
    int Q;	scanf("%d", &Q);
    rep(i,Q)	qq[i].read(i);
    sort(qq, qq+Q);
    int s1=0, nowq=0;
    FOR(i,1,n) {
    	for(auto x : L[i]) {
    		for(; x<=n; x+=x&-x)
    			++s[x];
    		++s1;
    	}
    	while(nowq<Q && qq[nowq].r == i)
    		ans[qq[nowq].id] = s1-getsum(qq[nowq].l-1), ++nowq;
    }
    rep(i,Q)
    	printf("%d\n", ans[i]<<1);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define TR(i,v)         for(__typeof((v).begin())i=(v).begin();i!=(v).end();++i)
#define DEBUG(x)        cout << #x << " = "; cout << x << endl;
#define SIZE(p)         (int)(p).size()
#define MP(a, b)        make_pair((a), (b))
#define ALL(p)          (p).begin(), (p).end()
#define rep(i, n)       for(int (i)=0; (i)<(int)(n); ++(i))
#define REP(i, a, n)    for(int (i)=(a); (i)<(int)(n); ++(i))
#define FOR(i, a, b)    for(int (i)=(int)(a); (i)<=(int)(b); ++(i))
#define FORD(i, b, a)   for(int (i)=(int)(b); (i)>=(int)(a); --(i))
#define CLR(x, y)       memset((x), (y), sizeof((x)))
typedef long long LL;
typedef pair<int, int> pii;
char S[1000005];
int P[1000005],SIZE,CUR,ans[1000005];
struct QNode {
	int l,r,lb,id;
	friend bool operator<(const QNode &x,const QNode &y) {
		return MP(x.lb,x.r) < MP(y.lb,y.r);
	}
	bool isSmall() {
		return r-l+1<=SIZE;
	}
}qq[100005];
int R1,R2,vis[1000005], temp_vis[1000005];
bool copied[1000005];
vector<int> copylist;
void init() {
	// CLR(vis,-1);
	TR(i,copylist)
		copied[*i]=0;
	// CLR(copied,0);
	R1=R2=0;
	copylist.clear();
}
void reset() {
	TR(i,copylist) {
		copied[*i]=0;
	}
	copylist.clear(),R2=0;
}
int get(int x) {
	return copied[x] ? temp_vis[x] : vis[x];
}
int ask(int L,int R) {
	FOR(i,L,R) if(~P[i]) {
		if(get(P[i])==CUR) {
			++R2;
		}
		copylist.push_back(i);		copied[i]=1;
		temp_vis[i]=CUR;
	}
	return R2;
}
int main(int argc, char const *argv[]) {
	#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	// freopen("C.out","w",stdout);
	#endif
	CLR(P,-1);
	scanf("%s", S+1);
	int n = strlen(S+1);
	stack<pair<char,int> > st;
	FOR(i,1,n) {
		if(S[i]==')') {
			if(!st.empty() && st.top().first == '(') {
				int a=st.top().second, b=i;
				P[a]=b,P[b]=a;
				st.pop();
			}
		}else
			st.push(MP('(',i));
	}
	for(SIZE=1;SIZE*SIZE<=n;++SIZE);
	init();
	int Q;	scanf("%d",&Q);
	rep(i,Q) {
		int l,r;	scanf("%d%d",&l,&r);
		qq[i] = (QNode){l,r,l/SIZE,i};
		if(qq[i].isSmall()) {
			CUR=Q+Q+i;
			ans[qq[i].id] = ask(qq[i].l,qq[i].r);
			reset();
		}
	}
	sort(qq,qq+Q);
	int preb=-1,nowr;
	rep(i,Q) {
		if(qq[i].isSmall())	continue;
		int l=qq[i].l,r=qq[i].r,lb=qq[i].lb, &res=ans[qq[i].id];
		res=0;
		// printf("[%d %d]\n",l,r);
		if(lb!=preb) {
			CUR=i+1;
			init();
			FOR(k,(lb+1)*SIZE,r) {
				if(~P[k]) {
					if(vis[P[k]] == CUR)
						++R1;
					vis[k]=CUR;
				}
			}
			nowr=r;
		}
		FOR(k,nowr+1,r) {
			if(~P[k]) {
				if(vis[P[k]] == CUR)
					++R1;
				vis[k]=CUR;
			}
		}
		nowr=r;
		R2=0;
		ask(l, (lb+1)*SIZE-1);
		res=R1+R2;
		preb=lb;
		reset();
	}
	rep(i,Q)
		printf("%d\n",ans[i]+ans[i]);
	return 0;
}


#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

struct nod {
    int ans,op,cl;
    nod(int _op=0,int _cl=0,int _ans=0) {
        ans=_ans;
        op=_op;
        cl=_cl;
    }
};

const int MAX_N=1000100;

nod aint[10*MAX_N];
nod sol;
string sir;

void merge(nod &s,nod st,nod dr) {
   s.ans=st.ans+dr.ans+min(st.op,dr.cl);
   s.op=st.op+dr.op-min(st.op,dr.cl);
   s.cl=st.cl+dr.cl-min(st.op,dr.cl);
}

void build(int poz,int st,int dr) {
    if(st==dr) {
        aint[poz]=nod(sir[st-1]=='(',sir[st-1]==')');
        return;
    }

    int mij=(st+dr)/2;
    build(poz*2,st,mij);
    build(poz*2+1,mij+1,dr);
    merge(aint[poz],aint[poz*2],aint[poz*2+1]);
}

void query(int poz,int st,int dr,const int &x,const int &y) {
    if(st>=x&&dr<=y) {
        merge(sol,sol,aint[poz]);
        return;
    }
    int mij=(st+dr)/2;
    if(x<=mij) {
        query(poz*2,st,mij,x,y);
    }
    if(y>=mij+1) {
        query(poz*2+1,mij+1,dr,x,y);
    }
}

int main() {
    cin>>sir;
    build(1,1,sir.size());
    int m;
    cin>>m;
    for(int i=1;i<=m;i++) {
        int x,y;
        sol=nod();
        cin>>x>>y;
        query(1,1,sir.size(),x,y);
        cout<<2*sol.ans<<'\n';
    }
    return 0;
}


#include <bitset>
#include <deque>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <algorithm>
#include <functional>
#include <iterator>
#include <locale>
#include <memory>
#include <stdexcept>
#include <utility>
#include <string>
#include <fstream>
#include <ios>
#include <iostream>
#include <iosfwd>
#include <iomanip>
#include <istream>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <complex>
#include <numeric>
#include <valarray>
#include <exception>
#include <limits>
#include <new>
#include <typeinfo>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <climits>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdlib>
#include <cstddef>
#include <cstdarg>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cwchar>
#include <cwctype>
using namespace std;
static const double EPS = 1e-8;
static const double PI = 4.0 * atan(1.0);
static const double PI2 = 8.0 * atan(1.0);
typedef long long ll;
typedef unsigned long long ull;

#define ALL(c) (c).begin(), (c).end()
#define CLEAR(v) memset(v,0,sizeof(v))
#define MP(a,b) make_pair((a),(b))
#define REP(i,n) for(int i=0;i<(int)n;++i)
#define ABS(a) ((a)>0?(a):-(a))
template<class T> T MIN(const T& a, const T& b) { return a < b ? a : b; }
template<class T> T MAX(const T& a, const T& b) { return a > b ? a : b; }
template<class T> void MIN_UPDATE(T& a, const T& b) { if (a > b) a = b; }
template<class T> void MAX_UPDATE(T& a, const T& b) { if (a < b) a = b; }

/*
*  Copyright (c) 2010 Daisuke Okanohara
*
*   Redistribution and use in source and binary forms, with or without
*   modification, are permitted provided that the following conditions
*   are met:
*
*   1. Redistributions of source code must retain the above Copyright
*      notice, this list of conditions and the following disclaimer.
*
*   2. Redistributions in binary form must reproduce the above Copyright
*      notice, this list of conditions and the following disclaimer in the
*      documentation and/or other materials provided with the distribution.
*
*   3. Neither the name of the authors nor the names of its contributors
*      may be used to endorse or promote products derived from this
*      software without specific prior written permission.
*/

namespace wat_array {

	enum {
		NOTFOUND = 0
	};

	class BitArray {

	private:
		enum {
			BLOCK_BITNUM = 64,
			TABLE_INTERVAL = 4,
		};

	public:
		BitArray();
		~BitArray();
		BitArray(unsigned int size);
		unsigned int length() const;
		unsigned int one_num() const;

		void Init(unsigned int size);
		void Clear();
		void SetBit(unsigned int bit, unsigned int pos);

		void Build();
		unsigned int Rank(unsigned int bit, unsigned int pos) const;
		unsigned int Select(unsigned int bit, unsigned int rank) const;
		unsigned int Lookup(unsigned int pos) const;

		static unsigned int PopCount(unsigned int x);
		static unsigned int PopCountMask(unsigned int x, unsigned int offset);
		static unsigned int SelectInBlock(unsigned int x, unsigned int rank);
		static unsigned int GetBitNum(unsigned int one_num, unsigned int num, unsigned int bit);
		void PrintForDebug(std::ostream& os) const;

		void Save(std::ostream& os) const;
		void Load(std::istream& is);

	private:
		unsigned int RankOne(unsigned int pos) const;
		unsigned int SelectOutBlock(unsigned int bit, unsigned int& rank) const;

	private:
		std::vector<unsigned int> bit_blocks_;
		std::vector<unsigned int> rank_tables_;
		unsigned int length_;
		unsigned int one_num_;
	};

	/**
	Wavelet Tree Array Library for array processing.

	Input: A[0...n], 0 <= A[i] < k,
	Space: n log_2 k bits

	Support many queries in O(log k) time and constant for n.
	*/

	struct ListResult{
		ListResult(unsigned int c, unsigned int freq) : c(c), freq(freq){}
		unsigned int c;
		unsigned int freq;
		bool operator < (const ListResult& lr) const {
			if (c != lr.c) return c < lr.c;
			return freq < lr.freq;
		}
	};

	class WatArray{
	public:
		/**
		* Constructor
		*/
		WatArray();

		/**
		* Destructor
		*/
		~WatArray();

		/**
		* Initialize an index from an array
		* @param An array to be initialized
		*/
		void Init(const std::vector<unsigned int>& array);

		void Init(const BitArray& ba, unsigned int width, unsigned int length);

		/**
		* Clear and release the resouces
		*/
		void Clear();

		/**
		* Lookup A[pos]
		* @param pos the position
		* @return return A[pos] if found, or return NOT_FOUND if pos >= length
		*/
		unsigned int Lookup(unsigned int pos) const;

		/**
		* Compute the rank = the frequency of a character 'c' in the prefix of the array A[0...pos)
		* @param c Character to be examined
		* @param pos The position of the prefix (not inclusive)
		* @return The frequency of a character 'c' in the prefix of the array A[0...pos)
		*         or NOT_FOUND if c >= alphabet_num or pos > length
		*/
		unsigned int Rank(unsigned int c, unsigned int pos) const;

		/**
		* Compute the select = the position of the (rank+1)-th occurence of 'c' in the array.
		* @param c Character to be examined
		* @param rank The rank of the character
		* @return The position of the (rank+1)-th occurence of 'c' in the array.
		*         or NOT_FOUND if c >= alphabet_num or rank > Freq(c)
		*/
		unsigned int Select(unsigned int c, unsigned int rank) const;

		/**
		* Compute the frequency of characters c' < c in the subarray A[0...pos)
		* @param c The upper bound of the characters
		* @param pos The position of the end of the prefix (not inclusive)
		* @return The frequency of characters c' < c in the prefix of the array A[0...pos)
		or NOTFOUND if c > alphabet_num or pos > length
		*/
		unsigned int RankLessThan(unsigned int c, unsigned int pos) const;

		/**
		* Compute the frequency of characters c' > c in the subarray A[0...pos)
		* @param c The lower bound of the characters
		* @param pos The position of the end of the prefix (not inclusive)
		* @return The frequency of characters c' < c in the prefix of the array A[0...pos)
		or NOTFOUND if c > alphabet_num or pos > length
		*/
		unsigned int RankMoreThan(unsigned int c, unsigned int pos) const;

		/**
		* Compute the frequency of characters c' < c, c'=c, and c' > c, in the subarray A[0...pos)
		* @param c The character
		* @param pos The position of the end of the prefix (not inclusive)
		* @param rank The frefquency of c in A[0...pos)
		* @param rank_less_than The frequency of c' < c in A[0...pos)
		* @param rank_more_than The frequency of c' > c in A[0...pos)
		*/
		void RankAll(unsigned int c, unsigned int pos, unsigned int& rank,
			unsigned int& rank_less_than, unsigned int& rank_more_than) const;

		/**
		* Compute the frequency of characters min_c <= c' < max_c in the subarray A[beg_pos ... end_pos)
		* @param min_c The smallerest character to be examined
		* @param max_c The uppker bound of the character to be examined
		* @param beg_pos The beginning position of the array (inclusive)
		* @param end_pos The ending position of the array (not inclusive)
		* @return The frequency of characters min_c <= c < max_c in the subarray A[beg_pos .. end_pos)
		or NOTFOUND if max_c > alphabet_num or end_pos > length
		*/
		unsigned int FreqRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos) const;

		/**
		* Range Max Query
		* @param beg_pos The beginning position
		* @param end_pos The ending position
		* @param pos The position where the largest value appeared in the subarray A[beg_pos .. end_pos)
		If there are many items having the largest values, the smallest pos will be reporeted
		* @param val The largest value appeared in the subarray A[beg_pos ... end_pos)
		*/
		void MaxRange(unsigned int beg_pos, unsigned int end_pos, unsigned int& pos, unsigned int& val) const;

		/**
		* Range Min Query
		* @param beg_pos The beginning position
		* @param end_pos The ending position
		* @param pos The position where the smallest value appeared in the subarray A[beg_pos .. end_pos)
		If there are many items having the smalles values, the smallest pos will be reporeted
		* @param val The smallest value appeared in the subarray A[beg_pos ... end_pos)
		*/
		void MinRange(unsigned int beg_pos, unsigned int end_pos, unsigned int& pos, unsigned int& val) const;

		/**
		* Range Quantile Query, Return the K-th smallest value in the subarray
		* @param beg_pos The beginning position
		* @param end_pos The ending position
		* @param k The order (should be smaller than end_pos - beg_pos).
		* @param pos The position where the k-th largest value appeared in the subarray A[beg_pos .. end_pos)
		If there are many items having the k-th largest values, the smallest pos will be reporeted
		* @param val The k-th largest value appeared in the subarray A[beg_pos ... end_pos)
		*/
		void QuantileRange(unsigned int beg_pos, unsigned int end_pos, unsigned int k, unsigned int& pos, unsigned int& val) const;

		/**
		* List the distinct characters appeared in A[beg_pos ... end_pos) from most frequent ones
		*/
		void ListModeRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos, unsigned int num, std::vector<ListResult>& res) const;

		/**
		* List the distinct characters in A[beg_pos ... end_pos) min_c <= c < max_c  from smallest ones
		* @param min_c The smallerest character to be examined
		* @param max_c The uppker bound of the character to be examined
		* @param beg_pos The beginning position of the array (inclusive)
		* @param end_pos The ending positin of the array (not inclusive)
		* @param num The maximum number of reporting results.
		* @param res The distinct chracters in the A[beg_pos ... end_pos) from smallest ones.
		*            Each item consists of c:character and freq: frequency of c.
		*/
		void ListMinRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos, unsigned int num, std::vector<ListResult>& res) const;

		/**
		* List the distinct characters appeared in A[beg_pos ... end_pos) from largest ones
		* @param min_c The smallerest character to be examined
		* @param max_c The uppker bound of the character to be examined
		* @param beg_pos The beginning position of the array (inclusive)
		* @param end_pos The ending positin of the array (not inclusive)
		* @param num The maximum number of reporting results.
		* @param res The distinct chracters in the A[beg_pos ... end_pos) from largestx ones.
		*            Each item consists of c:character and freq: frequency of c.
		*/
		void ListMaxRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos, unsigned int num, std::vector<ListResult>& res) const;

		/**
		* Compute the frequency of the character c
		* @param c The character to be examined
		* param Return the frequency of c in the array.
		*/
		unsigned int Freq(unsigned int c) const;

		/**
		* Compute the frequency of the characters
		* @param min_c The minimum character
		* @param max_c The maximum character
		* param Return the frequency of min_c <= c < max_c in the array.
		*/
		unsigned int FreqSum(unsigned int min_c, unsigned int max_c) const;

		/**
		* Return the number of alphabets in the array
		* @return The number of alphabet in the array
		*/
		unsigned int alphabet_num() const;

		/**
		* Return the length of the array
		* @return The length of the array
		*/
		unsigned int length() const;

		/**
		* Save the current status to a stream
		* @param os The output stream where the data is saved
		*/
		void Save(std::ostream& os) const;

		/**
		* Load the current status from a stream
		* @param is The input stream where the status is saved
		*/
		void Load(std::istream& is);

	private:
		unsigned int GetAlphabetNum(const std::vector<unsigned int>& array) const;
		unsigned int Log2(unsigned int x) const;
		unsigned int PrefixCode(unsigned int x, unsigned int len, unsigned int total_len) const;
		static unsigned int GetMSB(unsigned int x, unsigned int pos, unsigned int len);
		static unsigned int GetLSB(unsigned int x, unsigned int pos);
		void SetArray(const std::vector<unsigned int>& array);
		void SetOccs(const std::vector<unsigned int>& array);
		void GetBegPoses(const std::vector<unsigned int>& array, unsigned int alpha_bit_num,
			std::vector<std::vector<unsigned int> >& beg_poses) const;

		struct QueryOnNode{
			QueryOnNode(unsigned int beg_node, unsigned int end_node, unsigned int beg_pos, unsigned int end_pos,
			unsigned int depth, unsigned int prefix_char) :
			beg_node(beg_node), end_node(end_node), beg_pos(beg_pos), end_pos(end_pos),
			depth(depth), prefix_char(prefix_char) {}
			unsigned int beg_node;
			unsigned int end_node;
			unsigned int beg_pos;
			unsigned int end_pos;
			unsigned int depth;
			unsigned int prefix_char;
			void print() {
				std::cout << beg_node << " " << end_node << " "
					<< beg_pos << " " << end_pos << " "
					<< depth << " ";
				for (unsigned int i = 0; i < depth; ++i){
					std::cout << GetMSB(prefix_char, i, depth);
				}
				std::cout << std::endl;
			}
		};

		class ListModeComparator;
		class ListMinComparator;
		class ListMaxComparator;

		template <class Comparator>
		void ListRange(unsigned int min_c, unsigned int max_c,
			unsigned int beg_pos, unsigned int end_pos,
			unsigned int num, std::vector<ListResult>& res) const {
			res.clear();
			if (end_pos > length_ || beg_pos >= end_pos) return;

			std::priority_queue<QueryOnNode, std::vector<QueryOnNode>, Comparator> qons;
			qons.push(QueryOnNode(0, length_, beg_pos, end_pos, 0, 0));

			while (res.size() < num && !qons.empty()){
				QueryOnNode qon = qons.top();
				qons.pop();
				if (qon.depth >= alphabet_bit_num_){
					res.push_back(ListResult(qon.prefix_char, qon.end_pos - qon.beg_pos));
				}
				else {
					std::vector<QueryOnNode> next;
					ExpandNode(min_c, max_c, qon, next);
					for (size_t i = 0; i < next.size(); ++i){
						qons.push(next[i]);
					}
				}
			}
		}

		bool CheckPrefix(unsigned int prefix, unsigned int depth, unsigned int min_c, unsigned int max_c) const;
		void ExpandNode(unsigned int min_c, unsigned int max_c,
			const QueryOnNode& qon, std::vector<QueryOnNode>& next) const;

		std::vector<BitArray> bit_arrays_;
		BitArray occs_;

		unsigned int alphabet_num_;
		unsigned int alphabet_bit_num_;
		unsigned int length_;
	};

	BitArray::BitArray() : length_(0), one_num_(0){
	}

	BitArray::BitArray(unsigned int length){
		Init(length);
	}

	BitArray::~BitArray(){
	}

	unsigned int BitArray::length() const {
		return length_;
	}

	unsigned int BitArray::one_num() const{
		return one_num_;
	}

	void BitArray::Init(unsigned int length){
		length_ = length;
		one_num_ = 0;
		unsigned int block_num = (length + BLOCK_BITNUM - 1) / BLOCK_BITNUM;
		bit_blocks_.resize(block_num);
	}

	void BitArray::Clear(){
		std::vector<unsigned int>().swap(bit_blocks_);
		std::vector<unsigned int>().swap(rank_tables_);
		length_ = 0;
		one_num_ = 0;
	}

	void BitArray::Build() {
		one_num_ = 0;
		unsigned int table_num = ((bit_blocks_.size() + TABLE_INTERVAL - 1) / TABLE_INTERVAL) + 1;
		rank_tables_.resize(table_num);
		for (size_t i = 0; i < bit_blocks_.size(); ++i){
			if ((i % TABLE_INTERVAL) == 0){
				rank_tables_[i / TABLE_INTERVAL] = one_num_;
			}
			one_num_ += PopCount(bit_blocks_[i]);
		}
		rank_tables_.back() = one_num_;
	}

	void BitArray::SetBit(unsigned int bit, unsigned int pos) {
		if (!bit) return;
		bit_blocks_[pos / BLOCK_BITNUM] |= (1LLU << (pos % BLOCK_BITNUM));
	}

	unsigned int BitArray::Rank(unsigned int bit, unsigned int pos) const {
		if (pos > length_) return NOTFOUND;
		if (bit) return RankOne(pos);
		else return pos - RankOne(pos);
	}

	unsigned int BitArray::Select(unsigned int bit, unsigned int rank) const {
		if (bit){
			if (rank > one_num_) return NOTFOUND;
		}
		else {
			if (rank > length_ - one_num_) return NOTFOUND;
		}

		unsigned int block_pos = SelectOutBlock(bit, rank);
		unsigned int block = (bit) ? bit_blocks_[block_pos] : ~bit_blocks_[block_pos];
		return block_pos * BLOCK_BITNUM + SelectInBlock(block, rank);
	}

	unsigned int BitArray::SelectOutBlock(unsigned int bit, unsigned int& rank) const {
		// binary search over tables
		unsigned int left = 0;
		unsigned int right = rank_tables_.size();
		while (left < right){
			unsigned int mid = (left + right) / 2;
			unsigned int length = BLOCK_BITNUM * TABLE_INTERVAL * mid;
			if (GetBitNum(rank_tables_[mid], length, bit) < rank) {
				left = mid + 1;
			}
			else {
				right = mid;
			}
		}

		unsigned int table_ind = (left != 0) ? left - 1 : 0;
		unsigned int block_pos = table_ind * TABLE_INTERVAL;
		rank -= GetBitNum(rank_tables_[table_ind],
			block_pos * BLOCK_BITNUM,
			bit);

		// sequential search over blocks
		for (; block_pos < bit_blocks_.size(); ++block_pos){
			unsigned int rank_next = GetBitNum(PopCount(bit_blocks_[block_pos]), BLOCK_BITNUM, bit);
			if (rank <= rank_next){
				break;
			}
			rank -= rank_next;
		}
		return block_pos;
	}

	unsigned int BitArray::SelectInBlock(unsigned int x, unsigned int rank) {
		unsigned int x1 = x - ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1);
		unsigned int x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> 2) & 0x3333333333333333LLU);
		unsigned int x3 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FLLU;

		unsigned int pos = 0;
		for (;; pos += 8){
			unsigned int rank_next = (x3 >> pos) & 0xFFLLU;
			if (rank <= rank_next) break;
			rank -= rank_next;
		}

		unsigned int v2 = (x2 >> pos) & 0xFLLU;
		if (rank > v2) {
			rank -= v2;
			pos += 4;
		}

		unsigned int v1 = (x1 >> pos) & 0x3LLU;
		if (rank > v1){
			rank -= v1;
			pos += 2;
		}

		unsigned int v0 = (x >> pos) & 0x1LLU;
		if (v0 < rank){
			rank -= v0;
			pos += 1;
		}

		return pos;
	}

	unsigned int BitArray::Lookup(unsigned int pos) const {
		return (bit_blocks_[pos / BLOCK_BITNUM] >> (pos % BLOCK_BITNUM)) & 1LLU;
	}

	unsigned int BitArray::RankOne(unsigned int pos) const {
		unsigned int block_ind = pos / BLOCK_BITNUM;
		unsigned int table_ind = block_ind / TABLE_INTERVAL;
		assert(table_ind < rank_tables_.size());

		unsigned int rank = rank_tables_[table_ind];
		for (unsigned int i = table_ind * TABLE_INTERVAL; i < block_ind; ++i){
			rank += PopCount(bit_blocks_[i]);
		}
		rank += PopCountMask(bit_blocks_[block_ind], pos % BLOCK_BITNUM);
		return rank;
	}

	unsigned int BitArray::PopCount(unsigned int x) {
		x = (x & 0x5555555555555555ULL) +
			((x >> 1) & 0x5555555555555555ULL);
		x = (x & 0x3333333333333333ULL) +
			((x >> 2) & 0x3333333333333333ULL);
		x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
		x = x + (x >> 8);
		x = x + (x >> 16);
		//x = x + (x >> 32);
		return x & 0x7FLLU;
	}

	unsigned int BitArray::PopCountMask(unsigned int x, unsigned int offset) {
		if (offset == 0) return 0;
		return PopCount(x & ((1LLU << offset) - 1));
	}

	unsigned int BitArray::GetBitNum(unsigned int one_num, unsigned int num, unsigned int bit) {
		if (bit) return one_num;
		else return num - one_num;
	}

	void BitArray::PrintForDebug(std::ostream& os) const {
		for (unsigned int i = 0; i < length_; ++i){
			if (Lookup(i)) os << "1";
			else           os << "0";
			if (((i + 1) % 8) == 0) {
				os << " ";
			}
		}
	}

	void BitArray::Save(std::ostream& os) const{
		os.write((const char*)(&length_), sizeof(length_));
		os.write((const char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size());
	}

	void BitArray::Load(std::istream& is){
		Clear();
		is.read((char*)(&length_), sizeof(length_));
		Init(length_);
		is.read((char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size());
		Build();
	}

	WatArray::WatArray() : alphabet_num_(0), alphabet_bit_num_(0), length_(0){
	}

	WatArray::~WatArray() {
	}

	void WatArray::Clear(){
		vector<BitArray>().swap(bit_arrays_);
		occs_.Clear();
		alphabet_num_ = 0;
		alphabet_bit_num_ = 0;
		length_ = 0;
	}

	void WatArray::Init(const vector<unsigned int>& array){
		Clear();
		alphabet_num_ = GetAlphabetNum(array);
		alphabet_bit_num_ = Log2(alphabet_num_);

		length_ = static_cast<unsigned int>(array.size());
		SetArray(array);
		SetOccs(array);
	}

	unsigned int WatArray::Lookup(unsigned int pos) const{
		if (pos >= length_) return NOTFOUND;
		unsigned int st = 0;
		unsigned int en = length_;
		unsigned int c = 0;
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			const BitArray& ba = bit_arrays_[i];
			unsigned int boundary = st + ba.Rank(0, en) - ba.Rank(0, st);
			unsigned int bit = ba.Lookup(st + pos);
			c <<= 1;
			if (bit){
				pos = ba.Rank(1, st + pos) - ba.Rank(1, st);
				st = boundary;
				c |= 1LLU;
			}
			else {
				pos = ba.Rank(0, st + pos) - ba.Rank(0, st);
				en = boundary;
			}

		}
		return c;
	}

	unsigned int WatArray::Rank(unsigned int c, unsigned int pos) const{
		unsigned int rank_less_than = 0;
		unsigned int rank_more_than = 0;
		unsigned int rank = 0;
		RankAll(c, pos, rank, rank_less_than, rank_more_than);
		return rank;
	}

	unsigned int WatArray::RankLessThan(unsigned int c, unsigned int pos) const{
		unsigned int rank_less_than = 0;
		unsigned int rank_more_than = 0;
		unsigned int rank = 0;
		RankAll(c, pos, rank, rank_less_than, rank_more_than);
		return rank_less_than;
	}

	unsigned int WatArray::RankMoreThan(unsigned int c, unsigned int pos) const{
		unsigned int rank_less_than = 0;
		unsigned int rank_more_than = 0;
		unsigned int rank = 0;
		RankAll(c, pos, rank, rank_less_than, rank_more_than);
		return rank_more_than;
	}

	void WatArray::RankAll(unsigned int c, unsigned int pos,
		unsigned int& rank, unsigned int& rank_less_than, unsigned int& rank_more_than) const{
		if (c >= alphabet_num_) {
			rank_less_than = NOTFOUND;
			rank_more_than = NOTFOUND;
			rank = NOTFOUND;
			return;
		}
		if (pos >= length_) {
			pos = length_;
		}
		unsigned int beg_node = 0;
		unsigned int end_node = length_;
		rank_less_than = 0;
		rank_more_than = 0;

		for (size_t i = 0; i < bit_arrays_.size() && beg_node < end_node; ++i){
			const BitArray& ba = bit_arrays_[i];
			unsigned int beg_node_zero = ba.Rank(0, beg_node);
			unsigned int beg_node_one = beg_node - beg_node_zero;
			unsigned int end_node_zero = ba.Rank(0, end_node);
			unsigned int boundary = beg_node + end_node_zero - beg_node_zero;
			unsigned int bit = GetMSB(c, i, bit_arrays_.size());
			if (!bit){
				rank_more_than += ba.Rank(1, pos) - beg_node_one;
				pos = beg_node + ba.Rank(0, pos) - beg_node_zero;
				end_node = boundary;
			}
			else {
				rank_less_than += ba.Rank(0, pos) - beg_node_zero;
				pos = boundary + ba.Rank(1, pos) - (beg_node - beg_node_zero);
				beg_node = boundary;
			}
		}
		rank = pos - beg_node;
	}

	unsigned int WatArray::Select(unsigned int c, unsigned int rank) const{
		if (c >= alphabet_num_) {
			return NOTFOUND;
		}
		if (rank > Freq(c)){
			return NOTFOUND;
		}

		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			unsigned int lower_c = c & ~((1LLU << (i + 1)) - 1);
			unsigned int beg_node = occs_.Select(1, lower_c + 1) - lower_c;
			const BitArray& ba = bit_arrays_[alphabet_bit_num_ - i - 1];
			unsigned int bit = GetLSB(c, i);
			unsigned int before_rank = ba.Rank(bit, beg_node);
			rank = ba.Select(bit, before_rank + rank) - beg_node + 1;
		}
		return rank - 1;
	}

	unsigned int WatArray::FreqRange(unsigned int min_c, unsigned int max_c, unsigned int begin_pos, unsigned int end_pos) const{
		if (min_c >= alphabet_num_) return 0;
		if (max_c <= min_c) return 0;
		if (end_pos > length_ || begin_pos > end_pos) return 0;
		return
			+RankLessThan(max_c, end_pos)
			- RankLessThan(min_c, end_pos)
			- RankLessThan(max_c, begin_pos)
			+ RankLessThan(min_c, begin_pos);
	}

	void WatArray::MaxRange(unsigned int begin_pos, unsigned int end_pos, unsigned int& pos, unsigned int& val) const {
		QuantileRange(begin_pos, end_pos, end_pos - begin_pos - 1, pos, val);
	}

	void WatArray::MinRange(unsigned int begin_pos, unsigned int end_pos, unsigned int& pos, unsigned int& val) const {
		QuantileRange(begin_pos, end_pos, 0, pos, val);
	}

	void WatArray::QuantileRange(unsigned int begin_pos, unsigned int end_pos, unsigned int k, unsigned int& pos, unsigned int& val) const {
		if (end_pos > length_ || begin_pos >= end_pos) {
			pos = NOTFOUND;
			val = NOTFOUND;
			return;
		}

		val = 0;
		unsigned int beg_node = 0;
		unsigned int end_node = length_;
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			const BitArray& ba = bit_arrays_[i];
			unsigned int beg_node_zero = ba.Rank(0, beg_node);
			unsigned int end_node_zero = ba.Rank(0, end_node);
			unsigned int beg_node_one = beg_node - beg_node_zero;
			unsigned int beg_zero = ba.Rank(0, begin_pos);
			unsigned int end_zero = ba.Rank(0, end_pos);
			unsigned int beg_one = begin_pos - beg_zero;
			unsigned int end_one = end_pos - end_zero;
			unsigned int boundary = beg_node + end_node_zero - beg_node_zero;

			if (end_zero - beg_zero > k){
				end_node = boundary;
				begin_pos = beg_node + beg_zero - beg_node_zero;
				end_pos = beg_node + end_zero - beg_node_zero;
				val = val << 1;
			}
			else {
				beg_node = boundary;
				begin_pos = boundary + beg_one - beg_node_one;
				end_pos = boundary + end_one - beg_node_one;
				val = (val << 1) + 1;
				k -= end_zero - beg_zero;
			}
		}

		unsigned int rank = begin_pos - beg_node;
		pos = Select(val, rank + 1);
	}

	class WatArray::ListModeComparator{
	public:
		ListModeComparator() {}
		bool operator() (const QueryOnNode& lhs,
			const QueryOnNode& rhs) const {
			if (lhs.end_pos - lhs.beg_pos != rhs.end_pos - rhs.beg_pos) {
				return lhs.end_pos - lhs.beg_pos < rhs.end_pos - rhs.beg_pos;
			}
			else if (lhs.depth != rhs.depth) {
				return lhs.depth < rhs.depth;
			}
			else {
				return lhs.beg_pos > rhs.beg_pos;
			}
		}
	};

	class WatArray::ListMinComparator{
	public:
		ListMinComparator() {}
		bool operator() (const QueryOnNode& lhs,
			const QueryOnNode& rhs) const {
			if (lhs.depth != rhs.depth)
				return lhs.depth < rhs.depth;
			else return lhs.beg_node > rhs.beg_node;
		}
	};

	class WatArray::ListMaxComparator{
	public:
		ListMaxComparator() {}
		bool operator() (const QueryOnNode& lhs,
			const QueryOnNode& rhs) const {
			if (lhs.depth != rhs.depth)
				return lhs.depth < rhs.depth;
			else return lhs.beg_node < rhs.beg_node;
		}
	};

	void WatArray::ListModeRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos,
		unsigned int num, vector<ListResult>& res) const {
		ListRange<ListModeComparator>(min_c, max_c, beg_pos, end_pos, num, res);
	}

	void WatArray::ListMinRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos,
		unsigned int num, vector<ListResult>& res) const {
		ListRange<ListMinComparator>(min_c, max_c, beg_pos, end_pos, num, res);
	}

	void WatArray::ListMaxRange(unsigned int min_c, unsigned int max_c, unsigned int beg_pos, unsigned int end_pos,
		unsigned int num, vector<ListResult>& res) const {
		ListRange<ListMaxComparator>(min_c, max_c, beg_pos, end_pos, num, res);
	}

	bool WatArray::CheckPrefix(unsigned int prefix, unsigned int depth, unsigned int min_c, unsigned int max_c) const {
		if (PrefixCode(min_c, depth, alphabet_bit_num_) <= prefix &&
			PrefixCode(max_c - 1, depth, alphabet_bit_num_) >= prefix) return true;
		else return false;
	}

	void WatArray::ExpandNode(unsigned int min_c, unsigned int max_c,
		const QueryOnNode& qon, vector<QueryOnNode>& next) const{
		const BitArray& ba = bit_arrays_[qon.depth];

		unsigned int beg_node_zero = ba.Rank(0, qon.beg_node);
		unsigned int end_node_zero = ba.Rank(0, qon.end_node);
		unsigned int beg_node_one = qon.beg_node - beg_node_zero;
		unsigned int beg_zero = ba.Rank(0, qon.beg_pos);
		unsigned int end_zero = ba.Rank(0, qon.end_pos);
		unsigned int beg_one = qon.beg_pos - beg_zero;
		unsigned int end_one = qon.end_pos - end_zero;
		unsigned int boundary = qon.beg_node + end_node_zero - beg_node_zero;
		if (end_zero - beg_zero > 0){ // child for zero
			unsigned int next_prefix = qon.prefix_char << 1;
			if (CheckPrefix(next_prefix, qon.depth + 1, min_c, max_c)) {
				next.push_back(QueryOnNode(qon.beg_node,
					boundary,
					qon.beg_node + beg_zero - beg_node_zero,
					qon.beg_node + end_zero - beg_node_zero,
					qon.depth + 1,
					next_prefix));
			}
		}
		if (end_one - beg_one > 0){ // child for one
			unsigned int next_prefix = (qon.prefix_char << 1) + 1;
			if (CheckPrefix(next_prefix, qon.depth + 1, min_c, max_c)) {
				next.push_back(QueryOnNode(boundary,
					qon.end_node,
					boundary + beg_one - beg_node_one,
					boundary + end_one - beg_node_one,
					qon.depth + 1,
					next_prefix));
			}
		}
	}

	unsigned int WatArray::Freq(unsigned int c) const {
		if (c >= alphabet_num_) return NOTFOUND;
		return occs_.Select(1, c + 2) - occs_.Select(1, c + 1) - 1;
	}

	unsigned int WatArray::FreqSum(unsigned int min_c, unsigned int max_c) const {
		if (max_c > alphabet_num_ || min_c > max_c) return NOTFOUND;
		return occs_.Select(1, max_c + 1) - occs_.Select(1, min_c + 1) - (max_c - min_c);
	}

	unsigned int WatArray::alphabet_num() const{
		return alphabet_num_;
	}

	unsigned int WatArray::length() const{
		return length_;
	}

	unsigned int WatArray::GetAlphabetNum(const std::vector<unsigned int>& array) const {
		unsigned int alphabet_num = 0;
		for (size_t i = 0; i < array.size(); ++i){
			if (array[i] >= alphabet_num){
				alphabet_num = array[i] + 1;
			}
		}
		return alphabet_num;
	}

	unsigned int WatArray::Log2(unsigned int x) const{
		if (x == 0) return 0;
		x--;
		unsigned int bit_num = 0;
		while (x >> bit_num){
			++bit_num;
		}
		return bit_num;
	}

	unsigned int WatArray::PrefixCode(unsigned int x, unsigned int len, unsigned int bit_num) const{
		return x >> (bit_num - len);
	}

	unsigned int WatArray::GetMSB(unsigned int x, unsigned int pos, unsigned int len) {
		return (x >> (len - (pos + 1))) & 1LLU;
	}

	unsigned int WatArray::GetLSB(unsigned int x, unsigned int pos) {
		return (x >> pos) & 1LLU;
	}

	void WatArray::SetArray(const vector<unsigned int>& array) {
		if (alphabet_num_ == 0) return;
		bit_arrays_.resize(alphabet_bit_num_, length_);

		vector<vector<unsigned int> > beg_poses;
		GetBegPoses(array, alphabet_bit_num_, beg_poses);

		for (size_t i = 0; i < array.size(); ++i){
			unsigned int c = array[i];
			for (unsigned int j = 0; j < alphabet_bit_num_; ++j){
				unsigned int prefix_code = PrefixCode(c, j, alphabet_bit_num_);
				unsigned int bit_pos = beg_poses[j][prefix_code]++;
				bit_arrays_[j].SetBit(GetMSB(c, j, alphabet_bit_num_), bit_pos);
			}
		}

		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			bit_arrays_[i].Build();
		}
	}

	void WatArray::SetOccs(const vector<unsigned int>& array){
		vector<unsigned int> counts(alphabet_num_);
		for (size_t i = 0; i < array.size(); ++i){
			counts[array[i]]++;
		}

		occs_.Init(array.size() + alphabet_num_ + 1);
		unsigned int sum = 0;
		for (size_t i = 0; i < counts.size(); ++i){
			occs_.SetBit(1, sum);
			sum += counts[i] + 1;
		}
		occs_.SetBit(1, sum);
		occs_.Build();
	}

	void WatArray::GetBegPoses(const vector<unsigned int>& array,
		unsigned int alpha_bit_num,
		vector< vector<unsigned int> >& beg_poses) const{
		beg_poses.resize(alpha_bit_num);
		for (unsigned int i = 0; i < beg_poses.size(); ++i){
			beg_poses[i].resize(1 << i);
		}

		for (size_t i = 0; i < array.size(); ++i){
			unsigned int c = array[i];
			for (unsigned int j = 0; j < alpha_bit_num; ++j){
				beg_poses[j][PrefixCode(c, j, alpha_bit_num)]++;
			}
		}

		for (size_t i = 0; i < beg_poses.size(); ++i){
			unsigned int sum = 0;
			vector<unsigned int>& beg_poses_level = beg_poses[i];
			for (size_t j = 0; j < beg_poses_level.size(); ++j){
				unsigned int num = beg_poses_level[j];
				beg_poses_level[j] = sum;
				sum += num;
			}
		}
	}

	void WatArray::Save(ostream& os) const{
		os.write((const char*)(&alphabet_num_), sizeof(alphabet_num_));
		os.write((const char*)(&length_), sizeof(length_));
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			bit_arrays_[i].Save(os);
		}
		occs_.Save(os);
	}

	void WatArray::Load(istream& is){
		Clear();
		is.read((char*)(&alphabet_num_), sizeof(alphabet_num_));
		alphabet_bit_num_ = Log2(alphabet_num_);
		is.read((char*)(&length_), sizeof(length_));

		bit_arrays_.resize(alphabet_bit_num_);
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			bit_arrays_[i].Load(is);
			bit_arrays_[i].Build();
		}
		occs_.Load(is);
		occs_.Build();
	}

}

int main() {
	std::ios::sync_with_stdio(false);

	static char buffer[1024 * 1024];
	scanf("%s", buffer);
	int n = strlen(buffer);

	vector<unsigned int> A(n + 1, (1 << 20) - 1);
	vector<int> stk;
	REP(i, n) {
		if (buffer[i] == '(') {
			stk.push_back(i + 1);
		}
		else {
			if (stk.empty()) {
				continue;
			}

			A[stk.back()] = i + 1;
			stk.pop_back();
		}
	}

	wat_array::WatArray wa;
	wa.Init(A);

	int m;
	scanf("%d", &m);
	REP(i, m) {
		int l, r;
		scanf("%d%d", &l, &r);

		cout << wa.FreqRange(0, r + 1, l, r + 1) * 2 << endl;;
	}
}


#include <bitset>
#include <deque>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <algorithm>
#include <functional>
#include <iterator>
#include <locale>
#include <memory>
#include <stdexcept>
#include <utility>
#include <string>
#include <fstream>
#include <ios>
#include <iostream>
#include <iosfwd>
#include <iomanip>
#include <istream>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <complex>
#include <numeric>
#include <valarray>
#include <exception>
#include <limits>
#include <new>
#include <typeinfo>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <climits>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdlib>
#include <cstddef>
#include <cstdarg>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cwchar>
#include <cwctype>
using namespace std;
static const double EPS = 1e-8;
static const double PI = 4.0 * atan(1.0);
static const double PI2 = 8.0 * atan(1.0);
typedef long long ll;
typedef unsigned long long ull;

#define ALL(c) (c).begin(), (c).end()
#define CLEAR(v) memset(v,0,sizeof(v))
#define MP(a,b) make_pair((a),(b))
#define REP(i,n) for(int i=0;i<(int)n;++i)
#define ABS(a) ((a)>0?(a):-(a))
template<class T> T MIN(const T& a, const T& b) { return a < b ? a : b; }
template<class T> T MAX(const T& a, const T& b) { return a > b ? a : b; }
template<class T> void MIN_UPDATE(T& a, const T& b) { if (a > b) a = b; }
template<class T> void MAX_UPDATE(T& a, const T& b) { if (a < b) a = b; }

#ifdef _MSC_VER
typedef unsigned long long uint64_t;
#endif
typedef unsigned long long ull;

/*
*  Copyright (c) 2010 Daisuke Okanohara
*
*   Redistribution and use in source and binary forms, with or without
*   modification, are permitted provided that the following conditions
*   are met:
*
*   1. Redistributions of source code must retain the above Copyright
*      notice, this list of conditions and the following disclaimer.
*
*   2. Redistributions in binary form must reproduce the above Copyright
*      notice, this list of conditions and the following disclaimer in the
*      documentation and/or other materials provided with the distribution.
*
*   3. Neither the name of the authors nor the names of its contributors
*      may be used to endorse or promote products derived from this
*      software without specific prior written permission.
*/

namespace wat_array {

	enum {
		NOTFOUND = 0
	};

	class BitArray {

	private:
		enum {
			BLOCK_BITNUM = 64,
			TABLE_INTERVAL = 4,
		};

	public:
		BitArray();
		~BitArray();
		BitArray(uint64_t size);
		uint64_t length() const;
		uint64_t one_num() const;

		void Init(uint64_t size);
		void Clear();
		void SetBit(uint64_t bit, uint64_t pos);

		void Build();
		uint64_t Rank(uint64_t bit, uint64_t pos) const;
		uint64_t Select(uint64_t bit, uint64_t rank) const;
		uint64_t Lookup(uint64_t pos) const;

		static uint64_t PopCount(uint64_t x);
		static uint64_t PopCountMask(uint64_t x, uint64_t offset);
		static uint64_t SelectInBlock(uint64_t x, uint64_t rank);
		static uint64_t GetBitNum(uint64_t one_num, uint64_t num, uint64_t bit);
		void PrintForDebug(std::ostream& os) const;

		void Save(std::ostream& os) const;
		void Load(std::istream& is);

	private:
		uint64_t RankOne(uint64_t pos) const;
		uint64_t SelectOutBlock(uint64_t bit, uint64_t& rank) const;

	private:
		std::vector<uint64_t> bit_blocks_;
		std::vector<uint64_t> rank_tables_;
		uint64_t length_;
		uint64_t one_num_;
	};

	/**
	Wavelet Tree Array Library for array processing.

	Input: A[0...n], 0 <= A[i] < k,
	Space: n log_2 k bits

	Support many queries in O(log k) time and constant for n.
	*/

	struct ListResult{
		ListResult(uint64_t c, uint64_t freq) : c(c), freq(freq){}
		uint64_t c;
		uint64_t freq;
		bool operator < (const ListResult& lr) const {
			if (c != lr.c) return c < lr.c;
			return freq < lr.freq;
		}
	};

	class WatArray{
	public:
		/**
		* Constructor
		*/
		WatArray();

		/**
		* Destructor
		*/
		~WatArray();

		/**
		* Initialize an index from an array
		* @param An array to be initialized
		*/
		void Init(const std::vector<uint64_t>& array);

		void Init(const BitArray& ba, uint64_t width, uint64_t length);

		/**
		* Clear and release the resouces
		*/
		void Clear();

		/**
		* Lookup A[pos]
		* @param pos the position
		* @return return A[pos] if found, or return NOT_FOUND if pos >= length
		*/
		uint64_t Lookup(uint64_t pos) const;

		/**
		* Compute the rank = the frequency of a character 'c' in the prefix of the array A[0...pos)
		* @param c Character to be examined
		* @param pos The position of the prefix (not inclusive)
		* @return The frequency of a character 'c' in the prefix of the array A[0...pos)
		*         or NOT_FOUND if c >= alphabet_num or pos > length
		*/
		uint64_t Rank(uint64_t c, uint64_t pos) const;

		/**
		* Compute the select = the position of the (rank+1)-th occurence of 'c' in the array.
		* @param c Character to be examined
		* @param rank The rank of the character
		* @return The position of the (rank+1)-th occurence of 'c' in the array.
		*         or NOT_FOUND if c >= alphabet_num or rank > Freq(c)
		*/
		uint64_t Select(uint64_t c, uint64_t rank) const;

		/**
		* Compute the frequency of characters c' < c in the subarray A[0...pos)
		* @param c The upper bound of the characters
		* @param pos The position of the end of the prefix (not inclusive)
		* @return The frequency of characters c' < c in the prefix of the array A[0...pos)
		or NOTFOUND if c > alphabet_num or pos > length
		*/
		uint64_t RankLessThan(uint64_t c, uint64_t pos) const;

		/**
		* Compute the frequency of characters c' > c in the subarray A[0...pos)
		* @param c The lower bound of the characters
		* @param pos The position of the end of the prefix (not inclusive)
		* @return The frequency of characters c' < c in the prefix of the array A[0...pos)
		or NOTFOUND if c > alphabet_num or pos > length
		*/
		uint64_t RankMoreThan(uint64_t c, uint64_t pos) const;

		/**
		* Compute the frequency of characters c' < c, c'=c, and c' > c, in the subarray A[0...pos)
		* @param c The character
		* @param pos The position of the end of the prefix (not inclusive)
		* @param rank The frefquency of c in A[0...pos)
		* @param rank_less_than The frequency of c' < c in A[0...pos)
		* @param rank_more_than The frequency of c' > c in A[0...pos)
		*/
		void RankAll(uint64_t c, uint64_t pos, uint64_t& rank,
			uint64_t& rank_less_than, uint64_t& rank_more_than) const;

		/**
		* Compute the frequency of characters min_c <= c' < max_c in the subarray A[beg_pos ... end_pos)
		* @param min_c The smallerest character to be examined
		* @param max_c The uppker bound of the character to be examined
		* @param beg_pos The beginning position of the array (inclusive)
		* @param end_pos The ending position of the array (not inclusive)
		* @return The frequency of characters min_c <= c < max_c in the subarray A[beg_pos .. end_pos)
		or NOTFOUND if max_c > alphabet_num or end_pos > length
		*/
		uint64_t FreqRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos) const;

		/**
		* Range Max Query
		* @param beg_pos The beginning position
		* @param end_pos The ending position
		* @param pos The position where the largest value appeared in the subarray A[beg_pos .. end_pos)
		If there are many items having the largest values, the smallest pos will be reporeted
		* @param val The largest value appeared in the subarray A[beg_pos ... end_pos)
		*/
		void MaxRange(uint64_t beg_pos, uint64_t end_pos, uint64_t& pos, uint64_t& val) const;

		/**
		* Range Min Query
		* @param beg_pos The beginning position
		* @param end_pos The ending position
		* @param pos The position where the smallest value appeared in the subarray A[beg_pos .. end_pos)
		If there are many items having the smalles values, the smallest pos will be reporeted
		* @param val The smallest value appeared in the subarray A[beg_pos ... end_pos)
		*/
		void MinRange(uint64_t beg_pos, uint64_t end_pos, uint64_t& pos, uint64_t& val) const;

		/**
		* Range Quantile Query, Return the K-th smallest value in the subarray
		* @param beg_pos The beginning position
		* @param end_pos The ending position
		* @param k The order (should be smaller than end_pos - beg_pos).
		* @param pos The position where the k-th largest value appeared in the subarray A[beg_pos .. end_pos)
		If there are many items having the k-th largest values, the smallest pos will be reporeted
		* @param val The k-th largest value appeared in the subarray A[beg_pos ... end_pos)
		*/
		void QuantileRange(uint64_t beg_pos, uint64_t end_pos, uint64_t k, uint64_t& pos, uint64_t& val) const;

		/**
		* List the distinct characters appeared in A[beg_pos ... end_pos) from most frequent ones
		*/
		void ListModeRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos, uint64_t num, std::vector<ListResult>& res) const;

		/**
		* List the distinct characters in A[beg_pos ... end_pos) min_c <= c < max_c  from smallest ones
		* @param min_c The smallerest character to be examined
		* @param max_c The uppker bound of the character to be examined
		* @param beg_pos The beginning position of the array (inclusive)
		* @param end_pos The ending positin of the array (not inclusive)
		* @param num The maximum number of reporting results.
		* @param res The distinct chracters in the A[beg_pos ... end_pos) from smallest ones.
		*            Each item consists of c:character and freq: frequency of c.
		*/
		void ListMinRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos, uint64_t num, std::vector<ListResult>& res) const;

		/**
		* List the distinct characters appeared in A[beg_pos ... end_pos) from largest ones
		* @param min_c The smallerest character to be examined
		* @param max_c The uppker bound of the character to be examined
		* @param beg_pos The beginning position of the array (inclusive)
		* @param end_pos The ending positin of the array (not inclusive)
		* @param num The maximum number of reporting results.
		* @param res The distinct chracters in the A[beg_pos ... end_pos) from largestx ones.
		*            Each item consists of c:character and freq: frequency of c.
		*/
		void ListMaxRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos, uint64_t num, std::vector<ListResult>& res) const;

		/**
		* Compute the frequency of the character c
		* @param c The character to be examined
		* param Return the frequency of c in the array.
		*/
		uint64_t Freq(uint64_t c) const;

		/**
		* Compute the frequency of the characters
		* @param min_c The minimum character
		* @param max_c The maximum character
		* param Return the frequency of min_c <= c < max_c in the array.
		*/
		uint64_t FreqSum(uint64_t min_c, uint64_t max_c) const;

		/**
		* Return the number of alphabets in the array
		* @return The number of alphabet in the array
		*/
		uint64_t alphabet_num() const;

		/**
		* Return the length of the array
		* @return The length of the array
		*/
		uint64_t length() const;

		/**
		* Save the current status to a stream
		* @param os The output stream where the data is saved
		*/
		void Save(std::ostream& os) const;

		/**
		* Load the current status from a stream
		* @param is The input stream where the status is saved
		*/
		void Load(std::istream& is);

	private:
		uint64_t GetAlphabetNum(const std::vector<uint64_t>& array) const;
		uint64_t Log2(uint64_t x) const;
		uint64_t PrefixCode(uint64_t x, uint64_t len, uint64_t total_len) const;
		static uint64_t GetMSB(uint64_t x, uint64_t pos, uint64_t len);
		static uint64_t GetLSB(uint64_t x, uint64_t pos);
		void SetArray(const std::vector<uint64_t>& array);
		void SetOccs(const std::vector<uint64_t>& array);
		void GetBegPoses(const std::vector<uint64_t>& array, uint64_t alpha_bit_num,
			std::vector<std::vector<uint64_t> >& beg_poses) const;

		struct QueryOnNode{
			QueryOnNode(uint64_t beg_node, uint64_t end_node, uint64_t beg_pos, uint64_t end_pos,
			uint64_t depth, uint64_t prefix_char) :
			beg_node(beg_node), end_node(end_node), beg_pos(beg_pos), end_pos(end_pos),
			depth(depth), prefix_char(prefix_char) {}
			uint64_t beg_node;
			uint64_t end_node;
			uint64_t beg_pos;
			uint64_t end_pos;
			uint64_t depth;
			uint64_t prefix_char;
			void print() {
				std::cout << beg_node << " " << end_node << " "
					<< beg_pos << " " << end_pos << " "
					<< depth << " ";
				for (uint64_t i = 0; i < depth; ++i){
					std::cout << GetMSB(prefix_char, i, depth);
				}
				std::cout << std::endl;
			}
		};

		class ListModeComparator;
		class ListMinComparator;
		class ListMaxComparator;

		template <class Comparator>
		void ListRange(uint64_t min_c, uint64_t max_c,
			uint64_t beg_pos, uint64_t end_pos,
			uint64_t num, std::vector<ListResult>& res) const {
			res.clear();
			if (end_pos > length_ || beg_pos >= end_pos) return;

			std::priority_queue<QueryOnNode, std::vector<QueryOnNode>, Comparator> qons;
			qons.push(QueryOnNode(0, length_, beg_pos, end_pos, 0, 0));

			while (res.size() < num && !qons.empty()){
				QueryOnNode qon = qons.top();
				qons.pop();
				if (qon.depth >= alphabet_bit_num_){
					res.push_back(ListResult(qon.prefix_char, qon.end_pos - qon.beg_pos));
				}
				else {
					std::vector<QueryOnNode> next;
					ExpandNode(min_c, max_c, qon, next);
					for (size_t i = 0; i < next.size(); ++i){
						qons.push(next[i]);
					}
				}
			}
		}

		bool CheckPrefix(uint64_t prefix, uint64_t depth, uint64_t min_c, uint64_t max_c) const;
		void ExpandNode(uint64_t min_c, uint64_t max_c,
			const QueryOnNode& qon, std::vector<QueryOnNode>& next) const;

		std::vector<BitArray> bit_arrays_;
		BitArray occs_;

		uint64_t alphabet_num_;
		uint64_t alphabet_bit_num_;
		uint64_t length_;
	};

	BitArray::BitArray() : length_(0), one_num_(0){
	}

	BitArray::BitArray(uint64_t length){
		Init(length);
	}

	BitArray::~BitArray(){
	}

	uint64_t BitArray::length() const {
		return length_;
	}

	uint64_t BitArray::one_num() const{
		return one_num_;
	}

	void BitArray::Init(uint64_t length){
		length_ = length;
		one_num_ = 0;
		uint64_t block_num = (length + BLOCK_BITNUM - 1) / BLOCK_BITNUM;
		bit_blocks_.resize(block_num);
	}

	void BitArray::Clear(){
		std::vector<uint64_t>().swap(bit_blocks_);
		std::vector<uint64_t>().swap(rank_tables_);
		length_ = 0;
		one_num_ = 0;
	}

	void BitArray::Build() {
		one_num_ = 0;
		uint64_t table_num = ((bit_blocks_.size() + TABLE_INTERVAL - 1) / TABLE_INTERVAL) + 1;
		rank_tables_.resize(table_num);
		for (size_t i = 0; i < bit_blocks_.size(); ++i){
			if ((i % TABLE_INTERVAL) == 0){
				rank_tables_[i / TABLE_INTERVAL] = one_num_;
			}
			one_num_ += PopCount(bit_blocks_[i]);
		}
		rank_tables_.back() = one_num_;
	}

	void BitArray::SetBit(uint64_t bit, uint64_t pos) {
		if (!bit) return;
		bit_blocks_[pos / BLOCK_BITNUM] |= (1LLU << (pos % BLOCK_BITNUM));
	}

	uint64_t BitArray::Rank(uint64_t bit, uint64_t pos) const {
		if (pos > length_) return NOTFOUND;
		if (bit) return RankOne(pos);
		else return pos - RankOne(pos);
	}

	uint64_t BitArray::Select(uint64_t bit, uint64_t rank) const {
		if (bit){
			if (rank > one_num_) return NOTFOUND;
		}
		else {
			if (rank > length_ - one_num_) return NOTFOUND;
		}

		uint64_t block_pos = SelectOutBlock(bit, rank);
		uint64_t block = (bit) ? bit_blocks_[block_pos] : ~bit_blocks_[block_pos];
		return block_pos * BLOCK_BITNUM + SelectInBlock(block, rank);
	}

	uint64_t BitArray::SelectOutBlock(uint64_t bit, uint64_t& rank) const {
		// binary search over tables
		uint64_t left = 0;
		uint64_t right = rank_tables_.size();
		while (left < right){
			uint64_t mid = (left + right) / 2;
			uint64_t length = BLOCK_BITNUM * TABLE_INTERVAL * mid;
			if (GetBitNum(rank_tables_[mid], length, bit) < rank) {
				left = mid + 1;
			}
			else {
				right = mid;
			}
		}

		uint64_t table_ind = (left != 0) ? left - 1 : 0;
		uint64_t block_pos = table_ind * TABLE_INTERVAL;
		rank -= GetBitNum(rank_tables_[table_ind],
			block_pos * BLOCK_BITNUM,
			bit);

		// sequential search over blocks
		for (; block_pos < bit_blocks_.size(); ++block_pos){
			uint64_t rank_next = GetBitNum(PopCount(bit_blocks_[block_pos]), BLOCK_BITNUM, bit);
			if (rank <= rank_next){
				break;
			}
			rank -= rank_next;
		}
		return block_pos;
	}

	uint64_t BitArray::SelectInBlock(uint64_t x, uint64_t rank) {
		uint64_t x1 = x - ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1);
		uint64_t x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> 2) & 0x3333333333333333LLU);
		uint64_t x3 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FLLU;

		uint64_t pos = 0;
		for (;; pos += 8){
			uint64_t rank_next = (x3 >> pos) & 0xFFLLU;
			if (rank <= rank_next) break;
			rank -= rank_next;
		}

		uint64_t v2 = (x2 >> pos) & 0xFLLU;
		if (rank > v2) {
			rank -= v2;
			pos += 4;
		}

		uint64_t v1 = (x1 >> pos) & 0x3LLU;
		if (rank > v1){
			rank -= v1;
			pos += 2;
		}

		uint64_t v0 = (x >> pos) & 0x1LLU;
		if (v0 < rank){
			rank -= v0;
			pos += 1;
		}

		return pos;
	}

	uint64_t BitArray::Lookup(uint64_t pos) const {
		return (bit_blocks_[pos / BLOCK_BITNUM] >> (pos % BLOCK_BITNUM)) & 1LLU;
	}

	uint64_t BitArray::RankOne(uint64_t pos) const {
		uint64_t block_ind = pos / BLOCK_BITNUM;
		uint64_t table_ind = block_ind / TABLE_INTERVAL;
		assert(table_ind < rank_tables_.size());

		uint64_t rank = rank_tables_[table_ind];
		for (uint64_t i = table_ind * TABLE_INTERVAL; i < block_ind; ++i){
			rank += PopCount(bit_blocks_[i]);
		}
		rank += PopCountMask(bit_blocks_[block_ind], pos % BLOCK_BITNUM);
		return rank;
	}

	uint64_t BitArray::PopCount(uint64_t x) {
		x = (x & 0x5555555555555555ULL) +
			((x >> 1) & 0x5555555555555555ULL);
		x = (x & 0x3333333333333333ULL) +
			((x >> 2) & 0x3333333333333333ULL);
		x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
		x = x + (x >> 8);
		x = x + (x >> 16);
		x = x + (x >> 32);
		return x & 0x7FLLU;
	}

	uint64_t BitArray::PopCountMask(uint64_t x, uint64_t offset) {
		if (offset == 0) return 0;
		return PopCount(x & ((1LLU << offset) - 1));
	}

	uint64_t BitArray::GetBitNum(uint64_t one_num, uint64_t num, uint64_t bit) {
		if (bit) return one_num;
		else return num - one_num;
	}

	void BitArray::PrintForDebug(std::ostream& os) const {
		for (uint64_t i = 0; i < length_; ++i){
			if (Lookup(i)) os << "1";
			else           os << "0";
			if (((i + 1) % 8) == 0) {
				os << " ";
			}
		}
	}

	void BitArray::Save(std::ostream& os) const{
		os.write((const char*)(&length_), sizeof(length_));
		os.write((const char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size());
	}

	void BitArray::Load(std::istream& is){
		Clear();
		is.read((char*)(&length_), sizeof(length_));
		Init(length_);
		is.read((char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size());
		Build();
	}

	WatArray::WatArray() : alphabet_num_(0), alphabet_bit_num_(0), length_(0){
	}

	WatArray::~WatArray() {
	}

	void WatArray::Clear(){
		vector<BitArray>().swap(bit_arrays_);
		occs_.Clear();
		alphabet_num_ = 0;
		alphabet_bit_num_ = 0;
		length_ = 0;
	}

	void WatArray::Init(const vector<uint64_t>& array){
		Clear();
		alphabet_num_ = GetAlphabetNum(array);
		alphabet_bit_num_ = Log2(alphabet_num_);

		length_ = static_cast<uint64_t>(array.size());
		SetArray(array);
		SetOccs(array);
	}

	uint64_t WatArray::Lookup(uint64_t pos) const{
		if (pos >= length_) return NOTFOUND;
		uint64_t st = 0;
		uint64_t en = length_;
		uint64_t c = 0;
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			const BitArray& ba = bit_arrays_[i];
			uint64_t boundary = st + ba.Rank(0, en) - ba.Rank(0, st);
			uint64_t bit = ba.Lookup(st + pos);
			c <<= 1;
			if (bit){
				pos = ba.Rank(1, st + pos) - ba.Rank(1, st);
				st = boundary;
				c |= 1LLU;
			}
			else {
				pos = ba.Rank(0, st + pos) - ba.Rank(0, st);
				en = boundary;
			}

		}
		return c;
	}

	uint64_t WatArray::Rank(uint64_t c, uint64_t pos) const{
		uint64_t rank_less_than = 0;
		uint64_t rank_more_than = 0;
		uint64_t rank = 0;
		RankAll(c, pos, rank, rank_less_than, rank_more_than);
		return rank;
	}

	uint64_t WatArray::RankLessThan(uint64_t c, uint64_t pos) const{
		uint64_t rank_less_than = 0;
		uint64_t rank_more_than = 0;
		uint64_t rank = 0;
		RankAll(c, pos, rank, rank_less_than, rank_more_than);
		return rank_less_than;
	}

	uint64_t WatArray::RankMoreThan(uint64_t c, uint64_t pos) const{
		uint64_t rank_less_than = 0;
		uint64_t rank_more_than = 0;
		uint64_t rank = 0;
		RankAll(c, pos, rank, rank_less_than, rank_more_than);
		return rank_more_than;
	}

	void WatArray::RankAll(uint64_t c, uint64_t pos,
		uint64_t& rank, uint64_t& rank_less_than, uint64_t& rank_more_than) const{
		if (c >= alphabet_num_) {
			rank_less_than = NOTFOUND;
			rank_more_than = NOTFOUND;
			rank = NOTFOUND;
			return;
		}
		if (pos >= length_) {
			pos = length_;
		}
		uint64_t beg_node = 0;
		uint64_t end_node = length_;
		rank_less_than = 0;
		rank_more_than = 0;

		for (size_t i = 0; i < bit_arrays_.size() && beg_node < end_node; ++i){
			const BitArray& ba = bit_arrays_[i];
			uint64_t beg_node_zero = ba.Rank(0, beg_node);
			uint64_t beg_node_one = beg_node - beg_node_zero;
			uint64_t end_node_zero = ba.Rank(0, end_node);
			uint64_t boundary = beg_node + end_node_zero - beg_node_zero;
			uint64_t bit = GetMSB(c, i, bit_arrays_.size());
			if (!bit){
				rank_more_than += ba.Rank(1, pos) - beg_node_one;
				pos = beg_node + ba.Rank(0, pos) - beg_node_zero;
				end_node = boundary;
			}
			else {
				rank_less_than += ba.Rank(0, pos) - beg_node_zero;
				pos = boundary + ba.Rank(1, pos) - (beg_node - beg_node_zero);
				beg_node = boundary;
			}
		}
		rank = pos - beg_node;
	}

	uint64_t WatArray::Select(uint64_t c, uint64_t rank) const{
		if (c >= alphabet_num_) {
			return NOTFOUND;
		}
		if (rank > Freq(c)){
			return NOTFOUND;
		}

		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			uint64_t lower_c = c & ~((1LLU << (i + 1)) - 1);
			uint64_t beg_node = occs_.Select(1, lower_c + 1) - lower_c;
			const BitArray& ba = bit_arrays_[alphabet_bit_num_ - i - 1];
			uint64_t bit = GetLSB(c, i);
			uint64_t before_rank = ba.Rank(bit, beg_node);
			rank = ba.Select(bit, before_rank + rank) - beg_node + 1;
		}
		return rank - 1;
	}

	uint64_t WatArray::FreqRange(uint64_t min_c, uint64_t max_c, uint64_t begin_pos, uint64_t end_pos) const{
		if (min_c >= alphabet_num_) return 0;
		if (max_c <= min_c) return 0;
		if (end_pos > length_ || begin_pos > end_pos) return 0;
		return
			+RankLessThan(max_c, end_pos)
			- RankLessThan(min_c, end_pos)
			- RankLessThan(max_c, begin_pos)
			+ RankLessThan(min_c, begin_pos);
	}

	void WatArray::MaxRange(uint64_t begin_pos, uint64_t end_pos, uint64_t& pos, uint64_t& val) const {
		QuantileRange(begin_pos, end_pos, end_pos - begin_pos - 1, pos, val);
	}

	void WatArray::MinRange(uint64_t begin_pos, uint64_t end_pos, uint64_t& pos, uint64_t& val) const {
		QuantileRange(begin_pos, end_pos, 0, pos, val);
	}

	void WatArray::QuantileRange(uint64_t begin_pos, uint64_t end_pos, uint64_t k, uint64_t& pos, uint64_t& val) const {
		if (end_pos > length_ || begin_pos >= end_pos) {
			pos = NOTFOUND;
			val = NOTFOUND;
			return;
		}

		val = 0;
		uint64_t beg_node = 0;
		uint64_t end_node = length_;
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			const BitArray& ba = bit_arrays_[i];
			uint64_t beg_node_zero = ba.Rank(0, beg_node);
			uint64_t end_node_zero = ba.Rank(0, end_node);
			uint64_t beg_node_one = beg_node - beg_node_zero;
			uint64_t beg_zero = ba.Rank(0, begin_pos);
			uint64_t end_zero = ba.Rank(0, end_pos);
			uint64_t beg_one = begin_pos - beg_zero;
			uint64_t end_one = end_pos - end_zero;
			uint64_t boundary = beg_node + end_node_zero - beg_node_zero;

			if (end_zero - beg_zero > k){
				end_node = boundary;
				begin_pos = beg_node + beg_zero - beg_node_zero;
				end_pos = beg_node + end_zero - beg_node_zero;
				val = val << 1;
			}
			else {
				beg_node = boundary;
				begin_pos = boundary + beg_one - beg_node_one;
				end_pos = boundary + end_one - beg_node_one;
				val = (val << 1) + 1;
				k -= end_zero - beg_zero;
			}
		}

		uint64_t rank = begin_pos - beg_node;
		pos = Select(val, rank + 1);
	}

	class WatArray::ListModeComparator{
	public:
		ListModeComparator() {}
		bool operator() (const QueryOnNode& lhs,
			const QueryOnNode& rhs) const {
			if (lhs.end_pos - lhs.beg_pos != rhs.end_pos - rhs.beg_pos) {
				return lhs.end_pos - lhs.beg_pos < rhs.end_pos - rhs.beg_pos;
			}
			else if (lhs.depth != rhs.depth) {
				return lhs.depth < rhs.depth;
			}
			else {
				return lhs.beg_pos > rhs.beg_pos;
			}
		}
	};

	class WatArray::ListMinComparator{
	public:
		ListMinComparator() {}
		bool operator() (const QueryOnNode& lhs,
			const QueryOnNode& rhs) const {
			if (lhs.depth != rhs.depth)
				return lhs.depth < rhs.depth;
			else return lhs.beg_node > rhs.beg_node;
		}
	};

	class WatArray::ListMaxComparator{
	public:
		ListMaxComparator() {}
		bool operator() (const QueryOnNode& lhs,
			const QueryOnNode& rhs) const {
			if (lhs.depth != rhs.depth)
				return lhs.depth < rhs.depth;
			else return lhs.beg_node < rhs.beg_node;
		}
	};

	void WatArray::ListModeRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos,
		uint64_t num, vector<ListResult>& res) const {
		ListRange<ListModeComparator>(min_c, max_c, beg_pos, end_pos, num, res);
	}

	void WatArray::ListMinRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos,
		uint64_t num, vector<ListResult>& res) const {
		ListRange<ListMinComparator>(min_c, max_c, beg_pos, end_pos, num, res);
	}

	void WatArray::ListMaxRange(uint64_t min_c, uint64_t max_c, uint64_t beg_pos, uint64_t end_pos,
		uint64_t num, vector<ListResult>& res) const {
		ListRange<ListMaxComparator>(min_c, max_c, beg_pos, end_pos, num, res);
	}

	bool WatArray::CheckPrefix(uint64_t prefix, uint64_t depth, uint64_t min_c, uint64_t max_c) const {
		if (PrefixCode(min_c, depth, alphabet_bit_num_) <= prefix &&
			PrefixCode(max_c - 1, depth, alphabet_bit_num_) >= prefix) return true;
		else return false;
	}

	void WatArray::ExpandNode(uint64_t min_c, uint64_t max_c,
		const QueryOnNode& qon, vector<QueryOnNode>& next) const{
		const BitArray& ba = bit_arrays_[qon.depth];

		uint64_t beg_node_zero = ba.Rank(0, qon.beg_node);
		uint64_t end_node_zero = ba.Rank(0, qon.end_node);
		uint64_t beg_node_one = qon.beg_node - beg_node_zero;
		uint64_t beg_zero = ba.Rank(0, qon.beg_pos);
		uint64_t end_zero = ba.Rank(0, qon.end_pos);
		uint64_t beg_one = qon.beg_pos - beg_zero;
		uint64_t end_one = qon.end_pos - end_zero;
		uint64_t boundary = qon.beg_node + end_node_zero - beg_node_zero;
		if (end_zero - beg_zero > 0){ // child for zero
			uint64_t next_prefix = qon.prefix_char << 1;
			if (CheckPrefix(next_prefix, qon.depth + 1, min_c, max_c)) {
				next.push_back(QueryOnNode(qon.beg_node,
					boundary,
					qon.beg_node + beg_zero - beg_node_zero,
					qon.beg_node + end_zero - beg_node_zero,
					qon.depth + 1,
					next_prefix));
			}
		}
		if (end_one - beg_one > 0){ // child for one
			uint64_t next_prefix = (qon.prefix_char << 1) + 1;
			if (CheckPrefix(next_prefix, qon.depth + 1, min_c, max_c)) {
				next.push_back(QueryOnNode(boundary,
					qon.end_node,
					boundary + beg_one - beg_node_one,
					boundary + end_one - beg_node_one,
					qon.depth + 1,
					next_prefix));
			}
		}
	}

	uint64_t WatArray::Freq(uint64_t c) const {
		if (c >= alphabet_num_) return NOTFOUND;
		return occs_.Select(1, c + 2) - occs_.Select(1, c + 1) - 1;
	}

	uint64_t WatArray::FreqSum(uint64_t min_c, uint64_t max_c) const {
		if (max_c > alphabet_num_ || min_c > max_c) return NOTFOUND;
		return occs_.Select(1, max_c + 1) - occs_.Select(1, min_c + 1) - (max_c - min_c);
	}

	uint64_t WatArray::alphabet_num() const{
		return alphabet_num_;
	}

	uint64_t WatArray::length() const{
		return length_;
	}

	uint64_t WatArray::GetAlphabetNum(const std::vector<uint64_t>& array) const {
		uint64_t alphabet_num = 0;
		for (size_t i = 0; i < array.size(); ++i){
			if (array[i] >= alphabet_num){
				alphabet_num = array[i] + 1;
			}
		}
		return alphabet_num;
	}

	uint64_t WatArray::Log2(uint64_t x) const{
		if (x == 0) return 0;
		x--;
		uint64_t bit_num = 0;
		while (x >> bit_num){
			++bit_num;
		}
		return bit_num;
	}

	uint64_t WatArray::PrefixCode(uint64_t x, uint64_t len, uint64_t bit_num) const{
		return x >> (bit_num - len);
	}

	uint64_t WatArray::GetMSB(uint64_t x, uint64_t pos, uint64_t len) {
		return (x >> (len - (pos + 1))) & 1LLU;
	}

	uint64_t WatArray::GetLSB(uint64_t x, uint64_t pos) {
		return (x >> pos) & 1LLU;
	}

	void WatArray::SetArray(const vector<uint64_t>& array) {
		if (alphabet_num_ == 0) return;
		bit_arrays_.resize(alphabet_bit_num_, length_);

		vector<vector<uint64_t> > beg_poses;
		GetBegPoses(array, alphabet_bit_num_, beg_poses);

		for (size_t i = 0; i < array.size(); ++i){
			uint64_t c = array[i];
			for (uint64_t j = 0; j < alphabet_bit_num_; ++j){
				uint64_t prefix_code = PrefixCode(c, j, alphabet_bit_num_);
				uint64_t bit_pos = beg_poses[j][prefix_code]++;
				bit_arrays_[j].SetBit(GetMSB(c, j, alphabet_bit_num_), bit_pos);
			}
		}

		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			bit_arrays_[i].Build();
		}
	}

	void WatArray::SetOccs(const vector<uint64_t>& array){
		vector<uint64_t> counts(alphabet_num_);
		for (size_t i = 0; i < array.size(); ++i){
			counts[array[i]]++;
		}

		occs_.Init(array.size() + alphabet_num_ + 1);
		uint64_t sum = 0;
		for (size_t i = 0; i < counts.size(); ++i){
			occs_.SetBit(1, sum);
			sum += counts[i] + 1;
		}
		occs_.SetBit(1, sum);
		occs_.Build();
	}

	void WatArray::GetBegPoses(const vector<uint64_t>& array,
		uint64_t alpha_bit_num,
		vector< vector<uint64_t> >& beg_poses) const{
		beg_poses.resize(alpha_bit_num);
		for (uint64_t i = 0; i < beg_poses.size(); ++i){
			beg_poses[i].resize(1 << i);
		}

		for (size_t i = 0; i < array.size(); ++i){
			uint64_t c = array[i];
			for (uint64_t j = 0; j < alpha_bit_num; ++j){
				beg_poses[j][PrefixCode(c, j, alpha_bit_num)]++;
			}
		}

		for (size_t i = 0; i < beg_poses.size(); ++i){
			uint64_t sum = 0;
			vector<uint64_t>& beg_poses_level = beg_poses[i];
			for (size_t j = 0; j < beg_poses_level.size(); ++j){
				uint64_t num = beg_poses_level[j];
				beg_poses_level[j] = sum;
				sum += num;
			}
		}
	}

	void WatArray::Save(ostream& os) const{
		os.write((const char*)(&alphabet_num_), sizeof(alphabet_num_));
		os.write((const char*)(&length_), sizeof(length_));
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			bit_arrays_[i].Save(os);
		}
		occs_.Save(os);
	}

	void WatArray::Load(istream& is){
		Clear();
		is.read((char*)(&alphabet_num_), sizeof(alphabet_num_));
		alphabet_bit_num_ = Log2(alphabet_num_);
		is.read((char*)(&length_), sizeof(length_));

		bit_arrays_.resize(alphabet_bit_num_);
		for (size_t i = 0; i < bit_arrays_.size(); ++i){
			bit_arrays_[i].Load(is);
			bit_arrays_[i].Build();
		}
		occs_.Load(is);
		occs_.Build();
	}

}

int main() {
	std::ios::sync_with_stdio(false);

	string s;
	cin >> s;

	vector<uint64_t> A(s.size() + 1, (1 << 20) - 1);
	vector<int> stk;
	REP(i, s.size()) {
		if (s[i] == '(') {
			stk.push_back(i + 1);
		}
		else {
			if (stk.empty()) {
				continue;
			}

			A[stk.back()] = i + 1;
			stk.pop_back();
		}
	}

	wat_array::WatArray wa;
	wa.Init(A);

	int m;
	cin >> m;
	REP(i, m) {
		int l, r;
		cin >> l >> r;

		cout << wa.FreqRange(0, r + 1, l, r + 1) * 2 << endl;;
	}
}