using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;

namespace CF
{
	internal class Program
	{
		private static void Main(string[] args)
		{
			using (var sr = new InputReader(Console.In))
			{
			//using (var sr = new InputReader(new StreamReader("input.txt")))
			//{
				var task = new Task();
				using (var sw = Console.Out) {
					//using (var sw = new StreamWriter("output.txt")) {
					task.Solve(sr, sw);
					//Console.ReadKey();//
				}
			}
		}
	}

	internal class Task
	{
		public void Solve(InputReader sr, TextWriter sw)
		{
			var array = sr.NextString().ToCharArray();
			var segmentTree = new SegmentTree(array);
			var n = sr.NextInt32();
			var sb = new StringBuilder();
			for (var i = 0; i < n; i++) {
				var input = sr.ReadArray(Int32.Parse);
				sb.AppendLine(segmentTree.Query(input[0] - 1, input[1] - 1).Sum.ToString());
			}

			sw.Write(sb);
		}
	}

	class SegmentTree
	{
		private Node[] tree;
		private int len;

		public SegmentTree(char[] array)
		{
			Build(array);
		}

		private void Build(char[] array)
		{
			var log = (int)Math.Ceiling(Math.Log(array.Length, 2));
			len = (int)Math.Pow(2, log);
			tree = new Node[len * 2];
			for (var i = 0; i < array.Length; i++) {
				var node = new Node();
				if (array[i] == '(')
					node.LeftCount++;
				if (array[i] == ')')
					node.RightCount++;

				tree[len + i] = node;
			}
			for (var i = array.Length; i < len; i++) {
				tree[i + len] = new Node();
			}
			for (var i = len - 1; i > 0; i--) {
				tree[i] = Combine(tree[i * 2], tree[i * 2 + 1]);
			}
		}

		private Node Combine(Node left, Node right)
		{
			var result = new Node {
				Sum = left.Sum + right.Sum
			};
			var min = Math.Min(left.LeftCount, right.RightCount);
			result.Sum += 2*min;
			result.LeftCount = left.LeftCount + right.LeftCount - min;
			result.RightCount = right.RightCount + left.RightCount - min;

			return result;
		}

		public Node Query(int l, int r)
		{
			var from = l + len;
			var to = r + len;
			var result = new Node();
			while (from <= to) {
				if (from % 2 == 1) {
					result = Combine(result, tree[from]);
				}
				if (to % 2 == 0) {
					result = Combine(result, tree[to]);
				}
				from = (from + 1) / 2;
				to = (to - 1) / 2;
			}

			return result;
		}

		public void Update(int i, int v)
		{
			//var indx = len + i;
			//var old = tree[indx];
			//tree[indx] = v;
			//indx /= 2;
			//while (indx > 0) {
			//	tree[indx] += -old + v;
			//	indx /= 2;
			//}
		}
	}

	class Node
	{
		public int LeftCount { get; set; }

		public int RightCount { get; set; }

		public int Sum { get; set; }
	}
}

internal class InputReader : IDisposable
{
	private bool isDispose;
	private readonly TextReader sr;

	public InputReader(TextReader stream)
	{
		sr = stream;
	}

	public void Dispose()
	{
		Dispose(true);
		GC.SuppressFinalize(this);
	}

	public string NextString()
	{
		var result = sr.ReadLine();
		return result;
	}

	public int NextInt32()
	{
		return Int32.Parse(NextString());
	}

	public long NextInt64()
	{
		return Int64.Parse(NextString());
	}

	public string[] NextSplitStrings()
	{
		return NextString()
						.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
	}

	public T[] ReadArray<T>(Func<string, CultureInfo, T> func)
	{
		return NextSplitStrings()
						.Select(s => func(s, CultureInfo.InvariantCulture))
						.ToArray();
	}

	public T[] ReadArrayFromString<T>(Func<string, CultureInfo, T> func, string str)
	{
		return
						str.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
										.Select(s => func(s, CultureInfo.InvariantCulture))
										.ToArray();
	}

	protected void Dispose(bool dispose)
	{
		if (!isDispose)
		{
			if (dispose)
				sr.Dispose();
			isDispose = true;
		}
	}

	~InputReader()
	{
		Dispose(false);
	}
}


using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;

namespace CF
{
	internal class Program
	{
		private static void Main(string[] args)
		{
			using (var sr = new InputReader(Console.In))
			{
			//using (var sr = new InputReader(new StreamReader("input.txt")))
			//{
				var task = new Task();
				using (var sw = Console.Out) {
					//using (var sw = new StreamWriter("output.txt")) {
					task.Solve(sr, sw);
					//Console.ReadKey();
				}
			}
		}
	}

	internal class Task
	{
		public void Solve(InputReader sr, TextWriter sw)
		{
			var array = sr.NextString().ToCharArray();
			var segmentTree = new SegmentTree(array);
			var n = sr.NextInt32();
			var sb = new StringBuilder();
			for (var i = 0; i < n; i++) {
				var input = sr.ReadArray(Int32.Parse);
				sb.AppendLine(segmentTree.Query(input[0] - 1, input[1] - 1).Sum.ToString());
			}

			sw.Write(sb);
		}
	}

	class SegmentTree
	{
		private Node[] tree;
		private int len;

		public SegmentTree(char[] array)
		{
			Build(array);
		}

		private void Build(char[] array)
		{
			var log = (int)Math.Ceiling(Math.Log(array.Length, 2));
			len = (int)Math.Pow(2, log);
			tree = new Node[len * 2];
			for (var i = 0; i < array.Length; i++) {
				var node = new Node();
				if (array[i] == '(')
					node.LeftCount++;
				if (array[i] == ')')
					node.RightCount++;

				tree[len + i] = node;
			}
			for (var i = array.Length; i < len; i++) {
				tree[i + len] = new Node();
			}
			for (var i = len - 1; i > 0; i--) {
				tree[i] = Combine(tree[i * 2], tree[i * 2 + 1]);
			}
		}

		private Node Combine(Node left, Node right)
		{
			var result = new Node {
				Sum = left.Sum + right.Sum
			};
			var min = Math.Min(left.LeftCount, right.RightCount);
			result.Sum += 2*min;
			result.LeftCount = left.LeftCount + right.LeftCount - min;
			result.RightCount = right.RightCount + left.RightCount - min;

			return result;
		}

		public Node Query(int l, int r)
		{
			var from = l + len;
			var to = r + len;
			var result = new Node();
			while (from <= to) {
				if (from % 2 == 1) {
					result = Combine(result, tree[from]);
				}
				if (to % 2 == 0) {
					result = Combine(result, tree[to]);
				}
				from = (from + 1) / 2;
				to = (to - 1) / 2;
			}

			return result;
		}

		public void Update(int i, int v)
		{
			//var indx = len + i;
			//var old = tree[indx];
			//tree[indx] = v;
			//indx /= 2;
			//while (indx > 0) {
			//	tree[indx] += -old + v;
			//	indx /= 2;
			//}
		}
	}

	class Node
	{
		public int LeftCount { get; set; }

		public int RightCount { get; set; }

		public int Sum { get; set; }
	}
}

internal class InputReader : IDisposable
{
	private bool isDispose;
	private readonly TextReader sr;

	public InputReader(TextReader stream)
	{
		sr = stream;
	}

	public void Dispose()
	{
		Dispose(true);
		GC.SuppressFinalize(this);
	}

	public string NextString()
	{
		var result = sr.ReadLine();
		return result;
	}

	public int NextInt32()
	{
		return Int32.Parse(NextString());
	}

	public long NextInt64()
	{
		return Int64.Parse(NextString());
	}

	public string[] NextSplitStrings()
	{
		return NextString()
						.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
	}

	public T[] ReadArray<T>(Func<string, CultureInfo, T> func)
	{
		return NextSplitStrings()
						.Select(s => func(s, CultureInfo.InvariantCulture))
						.ToArray();
	}

	public T[] ReadArrayFromString<T>(Func<string, CultureInfo, T> func, string str)
	{
		return
						str.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
										.Select(s => func(s, CultureInfo.InvariantCulture))
										.ToArray();
	}

	protected void Dispose(bool dispose)
	{
		if (!isDispose)
		{
			if (dispose)
				sr.Dispose();
			isDispose = true;
		}
	}

	~InputReader()
	{
		Dispose(false);
	}
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐ★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    class Bit
    {
        private readonly int size;
        private readonly int[] data;

        public Bit(int n)
        {
            size = n;
            data = new int[n];
        }

        public int PrefixSum(int r)
        {
            int ret = 0;
            for (; r >= 0; r = (r & r + 1) - 1)
                ret += data[r];
            return ret;
        }

        public int Sum(int l, int r)
        {
            return PrefixSum(r) - PrefixSum(l - 1);
        }

        public void Update(int idx, int diff)
        {
            for (; idx < size; idx = (idx | idx + 1))
                data[idx] += diff;
        }
    }

    public void Solve()
    {
        string s = ReadToken();
        int n = s.Length;

        int m = ReadInt();
        var q = new Tuple<int, int, int>[m];
        for (int i = 0; i < m; i++)
            q[i] = Tuple.Create(ReadInt() - 1, ReadInt() - 1, i);
        Array.Sort(q, (q1, q2) => q1.Item2.CompareTo(q2.Item2));

        var stack = new Stack<int>();
        var bit = new Bit(n);
        var ans = new int[m];
        int p = 0;
        for (int i = 0; i < n && p < m; i++)
        {
            if (s[i] == '(')
                stack.Push(i);
            else if (stack.Count > 0)
            {
                int x = stack.Pop();
                bit.Update(x, 1);
            }

            while (p < m && q[p].Item2 == i)
            {
                ans[q[p].Item3] = bit.Sum(q[p].Item1, i) * 2;
                p++;
            }
        }

        WriteLines(ans);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("hull.in");
        //writer = new StreamWriter("hull.out");
#endif
        try
        {
//            var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
//            thread.Start();
//            thread.Join();
            new Solver().Solve();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
#if DEBUG
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() {return reader.ReadLine().Split(new[] { ' ', '\t', '-' }, StringSplitOptions.RemoveEmptyEntries);}
    public static string ReadToken(){while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine());return currentLineTokens.Dequeue();}
    public static int ReadInt(){return int.Parse(ReadToken());}
    public static long ReadLong(){return long.Parse(ReadToken());}
    public static double ReadDouble(){return double.Parse(ReadToken(), CultureInfo.InvariantCulture);}
    public static int[] ReadIntArray(){return ReadAndSplitLine().Select(int.Parse).ToArray();}
    public static long[] ReadLongArray(){return ReadAndSplitLine().Select(long.Parse).ToArray();}
    public static double[] ReadDoubleArray(){return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray();}
    public static int[][] ReadIntMatrix(int numberOfRows){int[][] matrix = new int[numberOfRows][];for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray();return matrix;}
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows){int[][] matrix = ReadIntMatrix(numberOfRows);int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++){ret[i] = new int[numberOfRows];for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i];}return ret;}
    public static string[] ReadLines(int quantity){string[] lines = new string[quantity];for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim();return lines;}
    public static void WriteArray<T>(IEnumerable<T> array){writer.WriteLine(string.Join(" ", array));}
    public static void Write(params object[] array){WriteArray(array);}
    public static void WriteLines<T>(IEnumerable<T> array){foreach (var a in array)writer.WriteLine(a);}
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>{public new TValue this[TKey key]{
        get { return ContainsKey(key) ? base[key] : default(TValue); }set { base[key] = value; }}}
    private static T[] Init<T>(int size) where T : new(){var ret = new T[size];for (int i = 0; i < size; i++)ret[i] = new T();return ret;}
    #endregion
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public Interval(int min, int max)
            {
                Min = min; Max = max;
            }

            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;
            public int Count;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
                Count = 1;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
                node.Count++;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                if (interval.Contain(node.Min, node.Max))
                    return node.Count;
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && interval.Max >= node.Interval.Min)
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && interval.Min <= node.Left.Max)
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>();
            List<Interval> intervals = new List<Interval>(cad.Length / 2);
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        intervals.Add(new Interval(begin, i));
                    }
                }
            }
            Random rnd = new Random(0);
            for (int i = 0; i + 1 < intervals.Count; i++)
            {
                int index = rnd.Next(i + 1, intervals.Count - 1);
                Interval t = intervals[index]; intervals[index] = intervals[i]; intervals[i] = t;
            }
            for (int i = 0; i < intervals.Count; i++)
                tree.Insert(intervals[i]);
            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval(b, e));
                Console.WriteLine(count * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V3
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        struct State
        {
            public int Opened, Closed, Paired;

            public override string ToString()
            {
                return String.Format("{0}, {1}, {2}", Opened, Closed, Paired);
            }

            public static State FromBracket(char br)
            {
                if (br == '(') return new State() { Closed = 0, Opened = 1, Paired = 0 };
                return new State() { Closed = 1, Opened = 0, Paired = 0 };
            }
        }

        static int GetSize(int size)
        {
            return size * 3;
            int count = 0;
            while (size > 1)
            {
                count += size;
                size = (size + 1) / 2;
            }
            return count + 1;
        }

        static bool Update(int node, State[] array, int left, int right, string cad)
        {
            if (left > right) return false;
            if (left == right)
            {
                array[node] = State.FromBracket(cad[left]);
                return true;
            }
            int l = 2 * node + 1, r = l + 1;
            int mid = (left + right) / 2;
            bool cl = Update(l, array, left, mid, cad); bool cr = Update(r, array, mid + 1, right, cad);
            if (!cl && !cr) return false;
            State sl = cl ? array[l] : new State(); State sr = cr ? array[r] : new State();
            State state = new State();
            int m = Math.Min(sl.Opened, sr.Closed);
            state.Paired = sl.Paired + sr.Paired + m;
            state.Opened = sl.Opened + sr.Opened - m;
            state.Closed = sl.Closed + sr.Closed - m;
            array[node] = state;
            return true;
        }

        static State Query(int min, int max, int node, State[] array, int left, int right)
        {
            if (node >= array.Length || min > right || max < left || min > max) return new State();
            if (left == min && right == max)
                return array[node];
            int mid = (left + right) / 2;
            State ls = Query(min, Math.Min(max, mid), 2 * node + 1, array, left, mid);
            State rs = Query(Math.Max(mid + 1, min), max, 2 * node + 2, array, mid + 1, right);
            int m = Math.Min(ls.Opened, rs.Closed);
            return new State()
            {
                Paired = ls.Paired + rs.Paired + m,
                Closed = ls.Closed + rs.Closed - m,
                Opened = ls.Opened + rs.Opened - m
            };
        }

        static void Main(string[] args)
        {
            State[] rt = null;
            string cad = Console.ReadLine();
            rt = new State[GetSize(cad.Length)];
            Update(0, rt, 0, cad.Length - 1, cad);
            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                var result = Query(b, e, 0, rt, 0, cad.Length - 1);
                Console.WriteLine(result.Paired * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        struct Part : IComparable<Part>
        {
            public int Query;
            public int Begin;
            public int Index;
            public bool Closing;

            public int CompareTo(Part other)
            {
                if (Index == other.Index)
                    return (Closing ? 1 : 0) - (other.Closing ? 1 : 0);
                return Index - other.Index;
            }
        }

        class State
        {
            public int Last = 0;
            public int Current = 0;
            public int Total = 0;
            public int Sum = 0;
            public HashSet<int> Queries = new HashSet<int>();
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            int m = ReadInt();

            Part[] queries = new Part[2 * m];
            int[] result = new int[m];
            for (int i = 0, k = 0; i < m; i++)
            {
                int b = ReadInt(), e = ReadInt();
                queries[k++] = new Part() { Index = b - 1, Closing = false, Query = i };
                queries[k++] = new Part() { Begin = b - 1, Index = e - 1, Closing = true, Query = i };
            }
            Array.Sort<Part>(queries);
            Dictionary<int, State> states = new Dictionary<int, State>();
            int start = -1;
            for (int i = 0; i < queries.Length; i++)
            {
                var q = queries[i];
                if (states.Count == 0)
                    start = q.Index;
                if (!q.Closing)
                {
                    State state = new State() { Last = q.Index };
                    state.Queries.Add(q.Query);
                    while (i + 1 < queries.Length && !queries[i + 1].Closing && queries[i].Index == queries[i + 1].Index)
                    {
                        i++;
                        q = queries[i];
                        state.Queries.Add(q.Query);
                    }
                    states[state.Last] = state;
                }
                for (; start <= q.Index; start++)
                {
                    var br = cad[start];
                    foreach (var s in states.Values)
                    {
                        if (s.Last > start) continue;
                        if (br == '(')
                        {
                            if (s.Sum < 0)
                            {
                                s.Total += s.Current;
                                s.Last = start;
                                s.Sum = 0;
                                s.Current = 0;
                            }
                            s.Sum++;
                        }
                        else
                        {
                            if (s.Sum > 0)
                                s.Current += 2;
                            s.Sum--;
                        }
                    }
                }
                if (q.Closing)
                {
                    var state = states[q.Begin];
                    result[q.Query] = state.Total + state.Current;
                    states[q.Begin].Queries.Remove(q.Query);
                    if (states[q.Begin].Queries.Count == 0)
                        states.Remove(q.Begin);
                }
            }
            for (int i = 0; i < m; i++)
                Console.WriteLine(result[i]);
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public Interval(int min, int max)
            {
                Min = min; Max = max;
            }

            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }

            public bool Invalid(int min, int max)
            {
                return min > Max || max < Min;
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;
            public int Count;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
                Count = 1;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
                node.Count++;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                if (interval.Contain(node.Min, node.Max))
                    return node.Count;
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && !interval.Invalid(node.Right.Min, node.Right.Max))
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && !interval.Invalid(node.Left.Min, node.Left.Max))
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>();
            List<Interval> intervals = new List<Interval>(cad.Length / 2);
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        intervals.Add(new Interval(begin, i));
                    }
                }
            }
            Random rnd = new Random(0);
            for (int i = 0; i + 1 < intervals.Count; i++)
            {
                int index = rnd.Next(i + 1, intervals.Count - 1);
                Interval t = intervals[index]; intervals[index] = intervals[i]; intervals[i] = t;
            }
            for (int i = 0; i < intervals.Count; i++)
                tree.Insert(intervals[i]);

            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval(b, e));
                Console.WriteLine(count * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public Interval(int min, int max)
            {
                Min = min; Max = max;
            }

            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }

            public bool Invalid(int min, int max)
            {
                return min > Max || max < Min;
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;
            public int Count;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
                Count = 1;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
                node.Count++;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                if (interval.Invalid(node.Min, node.Max)) return 0;
                if (interval.Contain(node.Min, node.Max)) return node.Count;
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && !interval.Invalid(node.Right.Min, node.Right.Max))
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && !interval.Invalid(node.Left.Min, node.Left.Max))
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>(cad.Length / 2);
            List<Interval> intervals = new List<Interval>(cad.Length / 2);
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        intervals.Add(new Interval(begin, i));
                    }
                }
            }
            Random rnd = new Random(0);
            for (int i = 0; i + 1 < intervals.Count; i++)
            {
                int index = rnd.Next(i + 1, intervals.Count - 1);
                Interval t = intervals[index]; intervals[index] = intervals[i]; intervals[i] = t;
            }
            for (int i = 0; i < intervals.Count; i++)
                tree.Insert(intervals[i]);

            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval(b, e));
                Console.WriteLine(count * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V3
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        struct State
        {
            public int Opened, Closed, Paired;

            public override string ToString()
            {
                return String.Format("{0}, {1}, {2}", Opened, Closed, Paired);
            }

            public static State FromBracket(char br)
            {
                if (br == '(') return new State() { Closed = 0, Opened = 1, Paired = 0 };
                return new State() { Closed = 1, Opened = 0, Paired = 0 };
            }
        }

        static int GetSize(int size)
        {
            return size * 4;
            int count = 0;
            while (size > 1)
            {
                count += size;
                size = (size + 1) / 2;
            }
            return count + 1;
        }

        static bool Update(int node, State[] array, int left, int right, string cad)
        {
            if (left > right) return false;
            if (left == right)
            {
                array[node] = State.FromBracket(cad[left]);
                return true;
            }
            int l = 2 * node + 1, r = l + 1;
            int mid = (left + right) / 2;
            bool cl = Update(l, array, left, mid, cad); bool cr = Update(r, array, mid + 1, right, cad);
            if (!cl && !cr) return false;
            State sl = cl ? array[l] : new State(); State sr = cr ? array[r] : new State();
            State state = new State();
            int m = Math.Min(sl.Opened, sr.Closed);
            state.Paired = sl.Paired + sr.Paired + m;
            state.Opened = sl.Opened + sr.Opened - m;
            state.Closed = sl.Closed + sr.Closed - m;
            array[node] = state;
            return true;
        }

        static State Query(int min, int max, int node, State[] array, int left, int right)
        {
            if (node >= array.Length || min > right || max < left || min > max) return new State();
            if (left == min && right == max)
                return array[node];
            int mid = (left + right) / 2;
            State ls = Query(min, Math.Min(max, mid), 2 * node + 1, array, left, mid);
            State rs = Query(Math.Max(mid + 1, min), max, 2 * node + 2, array, mid + 1, right);
            int m = Math.Min(ls.Opened, rs.Closed);
            return new State()
            {
                Paired = ls.Paired + rs.Paired + m,
                Closed = ls.Closed + rs.Closed - m,
                Opened = ls.Opened + rs.Opened - m
            };
        }

        static void Main(string[] args)
        {
            State[] rt = null;
            string cad = Console.ReadLine();
            rt = new State[GetSize(cad.Length)];
            Update(0, rt, 0, cad.Length - 1, cad);
            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                var result = Query(b, e, 0, rt, 0, cad.Length - 1);
                Console.WriteLine(result.Paired * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public Interval(int min, int max)
            {
                Min = min; Max = max;
            }

            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;
            public int Count;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
                Count = 1;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
                node.Count++;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                if (interval.Contain(node.Min, node.Max))
                    return node.Count;
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && interval.Max >= node.Interval.Min)
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && interval.Min <= node.Left.Max)
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>();
            List<Interval> intervals = new List<Interval>(cad.Length / 2);
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        intervals.Add(new Interval(begin, i));
                    }
                }
            }
            Random rnd = new Random();
            for (int i = 0; i + 1 < intervals.Count; i++)
            {
                int index = rnd.Next(i + 1, intervals.Count - 1);
                Interval t = intervals[index]; intervals[index] = intervals[i]; intervals[i] = t;
            }
            for (int i = 0; i < intervals.Count; i++)
                tree.Insert(intervals[i]);
            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval(b, e));
                Console.WriteLine(count * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;
            public int Count;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
                Count = 1;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
                node.Count++;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                if (interval.Contain(node.Min, node.Max)) return node.Count;
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && interval.Max >= node.Interval.Min)
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && interval.Min <= node.Left.Max)
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>();
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        tree.Insert(new Interval() { Min = begin, Max = i });
                    }
                }
            }
            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval() { Min = b, Max = e });
                Console.WriteLine(count * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public Interval(int min, int max)
            {
                Min = min; Max = max;
            }

            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }

            public bool Invalid(int min, int max)
            {
                return min > Max || max < Min;
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;
            public int Count;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
                Count = 1;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
                node.Count++;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                if (interval.Contain(node.Min, node.Max))
                    return node.Count;
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && !interval.Invalid(node.Right.Min, node.Right.Max))
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && !interval.Invalid(node.Left.Min, node.Left.Max))
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>(cad.Length / 2);
            List<Interval> intervals = new List<Interval>(cad.Length / 2);
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        intervals.Add(new Interval(begin, i));
                    }
                }
            }
            Random rnd = new Random(0);
            for (int i = 0; i + 1 < intervals.Count; i++)
            {
                int index = rnd.Next(i + 1, intervals.Count - 1);
                Interval t = intervals[index]; intervals[index] = intervals[i]; intervals[i] = t;
            }
            for (int i = 0; i < intervals.Count; i++)
                tree.Insert(intervals[i]);

            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval(b, e));
                Console.WriteLine(count * 2);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CF_380_C_V2
{
    class Program
    {
        static int ReadInt()
        {
            int last = Console.Read();
            while (true)
            {
                if (last >= '0' && last <= '9') break;
                last = Console.Read();
            }
            int value = last - '0';
            while (true)
            {
                last = Console.Read();
                if (last < '0' || last > '9') break;
                value = 10 * value + last - '0';
            }
            return value;
        }

        class Interval
        {
            public int Min, Max;

            public bool Contain(Interval other)
            {
                if (other == null) return false;
                return (Min <= other.Min) && (Max >= other.Max);
            }

            public bool Contain(int min, int max)
            {
                return (Min <= min) && (Max >= max);
            }
        }

        class AugmentedNode
        {
            public Interval Interval;
            public int Min, Max;
            public AugmentedNode Left, Right;

            public AugmentedNode(Interval interval)
            {
                Interval = interval;
                Min = Interval.Min;
                Max = Interval.Max;
            }
        }

        class AugmentedTree
        {
            AugmentedNode Root;

            public void Insert(Interval interval)
            {
                if (Root == null)
                {
                    Root = new AugmentedNode(interval);
                    return;
                }
                Insert(Root, interval);
            }

            void Insert(AugmentedNode node, Interval interval)
            {
                if (node.Interval.Min < interval.Min)
                {
                    if (node.Right == null)
                        node.Right = new AugmentedNode(interval);
                    else
                        Insert(node.Right, interval);
                }
                else
                {
                    if (node.Left == null)
                        node.Left = new AugmentedNode(interval);
                    else
                        Insert(node.Left, interval);
                }
                if (node.Left != null)
                {
                    if (node.Left.Max > node.Max) node.Max = node.Left.Max;
                    if (node.Left.Min < node.Min) node.Min = node.Left.Min;
                }
                if (node.Right != null && node.Right.Max > node.Max) node.Max = node.Right.Max;
            }

            public int GetContainedIntervals(Interval interval)
            {
                if (Root == null) return 0;
                return GetContainedIntervals(Root, interval);
            }

            int GetContainedIntervals(AugmentedNode node, Interval interval)
            {
                int count = interval.Contain(node.Interval) ? 1 : 0;
                if (node.Right != null && interval.Max >= node.Right.Min)
                    count += GetContainedIntervals(node.Right, interval);
                if (node.Left != null && interval.Min <= node.Left.Max)
                    count += GetContainedIntervals(node.Left, interval);
                return count;
            }
        }

        static void Main(string[] args)
        {
            string cad = Console.ReadLine();
            AugmentedTree tree = new AugmentedTree();
            Stack<int> opens = new Stack<int>();
            for (int i = 0; i < cad.Length; i++)
            {
                if (cad[i] == '(')
                    opens.Push(i);
                else
                {
                    if (opens.Count > 0)
                    {
                        int begin = opens.Pop();
                        tree.Insert(new Interval() { Min = begin, Max = i });
                    }
                }
            }
            int m = ReadInt();
            for (int i = 0; i < m; i++)
            {
                int b = ReadInt() - 1, e = ReadInt() - 1;
                int count = tree.GetContainedIntervals(new Interval() { Min = b, Max = e });
                Console.WriteLine(count * 2);
            }
        }
    }
}


import kotlin.math.min

class SegmentTree<T>(private val data: List<T>, private val operation: (T, T) -> T) {
	private val tree = MutableList<T?>(4 * data.size) { null }

	init {
		build(0, data.indices)
	}

	fun query(interval: IntRange, parent: Int = 0, borders: IntRange = data.indices): T? {
		if (borders outOf interval) return null
		if (borders insideOf interval) return tree[parent]

		val midBorders = borders.divide()
		val leftQuery = query(interval, parent.left(), midBorders.first)
		val rightQuery = query(interval, parent.right(), midBorders.second)

		return combine(leftQuery, rightQuery)
	}

	private fun build(parent: Int, borders: IntRange) {
		if (borders.isCollapsed()) {
			tree[parent] = data[borders.first]
		} else {
			val midBorders = borders.divide()

			build(parent.left(), midBorders.first)
			build(parent.right(), midBorders.second)

			tree[parent] = combine(tree[parent.left()], tree[parent.right()])
		}
	}

	private fun IntRange.divide(): Pair<IntRange, IntRange> {
		val mid = first + (last - first) / 2
		val left = first..mid
		val right = (mid + 1)..last

		return left to right
	}

	private fun combine(left: T?, right: T?): T? {
		if (left == null) return right
		if (right == null) return left

		return operation(left, right)
	}

	private infix fun IntRange.outOf(other: IntRange) = first > other.last || last < other.first

	private infix fun IntRange.insideOf(other: IntRange) = other.first <= first && last <= other.last

	private fun IntRange.isCollapsed() = first == last

	private fun Int.left() = this * 2 + 1

	private fun Int.right() = this * 2 + 2
}

data class Node(val balancedBrackets: Int, val openBrackets: Int, val closeBrackets: Int)

private fun nodeCombiner(n1: Node, n2: Node): Node {
	val balancedBrackets = min(n1.openBrackets, n2.closeBrackets)

	return Node(
		n1.balancedBrackets + n2.balancedBrackets + balancedBrackets,
		n1.openBrackets + n2.openBrackets - balancedBrackets,
		n1.closeBrackets + n2.closeBrackets - balancedBrackets
	)
}

private fun readInts() = readLine()!!.split(" ").map { it.toInt() }

fun main() {
	val brackets = readLine()!!.asIterable()

	val nodes = brackets.map {
		val openBrackets = if (it == '(') 1 else 0
		val closeBrackets = 1 - openBrackets

		Node(0, openBrackets, closeBrackets)
	}

	val segmentTree = SegmentTree(nodes, ::nodeCombiner)
	val m = readInts().first()

	repeat(m) {
		val (start, end) = readInts().map { it - 1 }

		println(segmentTree.query(start..end)!!.balancedBrackets * 2)
	}
}


import kotlin.math.min

class SegmentTree<T>(private val data: List<T>, private val operation: (T, T) -> T) {
	private val tree = MutableList<T?>(4 * data.size) { null }

	init {
		build(0, data.indices)
	}

	fun query(interval: IntRange, parent: Int = 0, borders: IntRange = data.indices): T? {
		if (borders outOf interval) return null
		if (borders insideOf interval) return tree[parent]

		val mid = borders.mid()
		val leftQuery = query(interval, parent.left(), borders.first..mid)
		val rightQuery = query(interval, parent.right(), (mid + 1)..borders.last)

		return combine(leftQuery, rightQuery)
	}

	private fun build(parent: Int, borders: IntRange) {
		if (borders.isCollapsed()) {
			tree[parent] = data[borders.first]
		} else {
			val mid = borders.mid()

			build(parent.left(), borders.first..mid)
			build(parent.right(), (mid + 1)..borders.last)

			tree[parent] = combine(tree[parent.left()], tree[parent.right()])
		}
	}

	private fun combine(left: T?, right: T?): T? {
		if (left == null) return right
		if (right == null) return left

		return operation(left, right)
	}

	private infix fun IntRange.outOf(other: IntRange) = first > other.last || last < other.first

	private infix fun IntRange.insideOf(other: IntRange) = other.first <= first && last <= other.last

	private fun IntRange.isCollapsed() = first == last

	private fun IntRange.mid() = first + (last - first) / 2

	private fun Int.left() = this * 2 + 1

	private fun Int.right() = this * 2 + 2
}

data class Node(val balancedBrackets: Int, val openBrackets: Int, val closeBrackets: Int)

private fun nodeCombiner(n1: Node, n2: Node): Node {
	val balancedBrackets = min(n1.openBrackets, n2.closeBrackets)

	return Node(
		n1.balancedBrackets + n2.balancedBrackets + balancedBrackets,
		n1.openBrackets + n2.openBrackets - balancedBrackets,
		n1.closeBrackets + n2.closeBrackets - balancedBrackets
	)
}

private fun readInts() = readLine()!!.split(" ").map { it.toInt() }

fun main() {
	val brackets = readLine()!!

	val nodes = brackets.map {
		val openBrackets = if (it == '(') 1 else 0

		Node(0, openBrackets, 1 - openBrackets)
	}

	val segmentTree = SegmentTree(nodes, ::nodeCombiner)
	val m = readInts().first()

	repeat(m) {
		val (start, end) = readInts().map { it - 1 }

		println(segmentTree.query(start..end)!!.balancedBrackets * 2)
	}
}


import kotlin.math.min

class SegmentTree<T>(private val data: List<T>, private val operation: (T, T) -> T) {
	private val tree = MutableList<T?>(4 * data.size) { null }

	init {
		build(0, data.indices)
	}

	fun query(interval: IntRange, parent: Int = 0, borders: IntRange = data.indices): T? {
		if (borders outOf interval) return null
		if (borders insideOf interval) return tree[parent]

		val midBorders = borders.divide()
		val leftQuery = query(interval, parent.left(), midBorders.first)
		val rightQuery = query(interval, parent.right(), midBorders.second)

		return combine(leftQuery, rightQuery)
	}

	private fun build(parent: Int, borders: IntRange) {
		if (borders.isCollapsed()) {
			tree[parent] = data[borders.first]
		} else {
			val midBorders = borders.divide()

			build(parent.left(), midBorders.first)
			build(parent.right(), midBorders.second)

			tree[parent] = combine(tree[parent.left()], tree[parent.right()])
		}
	}

	private fun IntRange.divide(): Pair<IntRange, IntRange> {
		val mid = first + (last - first) / 2
		val left = first..mid
		val right = (mid + 1)..last

		return left to right
	}

	private fun combine(left: T?, right: T?): T? {
		if (left == null) return right
		if (right == null) return left

		return operation(left, right)
	}

	private infix fun IntRange.outOf(other: IntRange) = first > other.last || last < other.first

	private infix fun IntRange.insideOf(other: IntRange) = other.first <= first && last <= other.last

	private fun IntRange.isCollapsed() = first == last

	private fun Int.left() = this * 2 + 1

	private fun Int.right() = this * 2 + 2
}

data class Node(val balancedBrackets: Int, val openBrackets: Int, val closeBrackets: Int)

private fun nodeCombiner(n1: Node, n2: Node): Node {
	val balancedBrackets = min(n1.openBrackets, n2.closeBrackets)

	return Node(
		n1.balancedBrackets + n2.balancedBrackets + balancedBrackets,
		n1.openBrackets + n2.openBrackets - balancedBrackets,
		n1.closeBrackets + n2.closeBrackets - balancedBrackets
	)
}

private fun readInts() = readLine()!!.split(" ").map { it.toInt() }

fun main() {
	val brackets = readLine()!!.toCharArray()

	val nodes = brackets.map {
		val openBrackets = if (it == '(') 1 else 0
		val closeBrackets = 1 - openBrackets

		Node(0, openBrackets, closeBrackets)
	}

	val segmentTree = SegmentTree(nodes, ::nodeCombiner)
	val m = readInts().first()

	repeat(m) {
		val (start, end) = readInts().map { it - 1 }

		println(segmentTree.query(start..end)!!.balancedBrackets * 2)
	}
}


import kotlin.math.min

class SegmentTree<T>(private val data: List<T>, private val operation: (T, T) -> T) {
	private val tree = MutableList<T?>(4 * data.size) { null }

	init {
		build(0, data.indices)
	}

	fun query(interval: IntRange, parent: Int = 0, borders: IntRange = data.indices): T? {
		if (borders outOf interval) return null
		if (borders insideOf interval) return tree[parent]

		val midBorders = borders.divide()
		val leftQuery = query(interval, parent.left(), midBorders.first)
		val rightQuery = query(interval, parent.right(), midBorders.second)

		return combine(leftQuery, rightQuery)
	}

	private fun build(parent: Int, borders: IntRange) {
		if (borders.isCollapsed()) {
			tree[parent] = data[borders.first]
		} else {
			val midBorders = borders.divide()

			build(parent.left(), midBorders.first)
			build(parent.right(), midBorders.second)

			tree[parent] = combine(tree[parent.left()], tree[parent.right()])
		}
	}

	private fun IntRange.divide(): Pair<IntRange, IntRange> {
		val mid = first + (last - first) / 2
		val left = first..mid
		val right = (mid + 1)..last

		return left to right
	}

	private fun combine(left: T?, right: T?): T? {
		if (left == null) return right
		if (right == null) return left

		return operation(left, right)
	}

	private infix fun IntRange.outOf(other: IntRange) = first > other.last || last < other.first

	private infix fun IntRange.insideOf(other: IntRange) = other.first <= first && last <= other.last

	private fun IntRange.isCollapsed() = first == last

	private fun Int.left() = this * 2 + 1

	private fun Int.right() = this * 2 + 2
}

data class Node(val balancedBrackets: Int, val openBrackets: Int, val closeBrackets: Int)

private fun nodeCombiner(n1: Node, n2: Node): Node {
	val balancedBrackets = min(n1.openBrackets, n2.closeBrackets)

	return Node(
		n1.balancedBrackets + n2.balancedBrackets + balancedBrackets,
		n1.openBrackets + n2.openBrackets - balancedBrackets,
		n1.closeBrackets + n2.closeBrackets - balancedBrackets
	)
}

private fun readInts() = readLine()!!.split(" ").map { it.toInt() }

fun main() {
	val brackets = readLine()!!.asIterable()

	val nodes = brackets.map {
		val openBrackets = if (it == '(') 1 else 0
		val closeBrackets = 1 - openBrackets

		Node(0, openBrackets, closeBrackets)
	}

	val segmentTree = SegmentTree(nodes, ::nodeCombiner)
	val m = readInts().first()

	repeat(m) {
		var (start, end) = readInts()

		start--
		end--

		println(segmentTree.query(start..end)!!.balancedBrackets * 2)
	}
}


import kotlin.math.min

fun main() {
	val brackets = readLn()

	val nodes = brackets.map {
		val openBrackets = if (it == '(') 1 else 0

		Node(0, openBrackets, 1 - openBrackets)
	}

	val segmentTree = SegmentTree(nodes, ::nodeCombiner)
	val m = readInts().first()
	val output = StringBuilder()

	repeat(m) {
		val (start, end) = readInts().map { it - 1 }

		output.append(segmentTree.query(start..end)?.balancedBrackets)
		output.append('\n')
	}

	println(output)
}

private fun readLn() = readLine()!!
private fun readInts() = readLn().split(" ").map { it.toInt() }

class SegmentTree<T>(private val data: List<T>, private val operation: (T, T) -> T) {
	private val tree = MutableList<T?>(4 * data.size) { null }

	init {
		build(0, data.indices)
	}

	fun query(interval: IntRange, parent: Int = 0, borders: IntRange = data.indices): T? {
		if (borders outOf interval) return null
		if (borders insideOf interval) return tree[parent]

		val mid = borders.mid()
		val leftQuery = query(interval, parent.left(), borders.first..mid)
		val rightQuery = query(interval, parent.right(), (mid + 1)..borders.last)

		return combine(leftQuery, rightQuery)
	}

	private fun build(parent: Int, borders: IntRange) {
		if (borders.isCollapsed()) {
			tree[parent] = data[borders.first]
		} else {
			val mid = borders.mid()

			build(parent.left(), borders.first..mid)
			build(parent.right(), (mid + 1)..borders.last)

			tree[parent] = combine(tree[parent.left()], tree[parent.right()])
		}
	}

	private fun combine(left: T?, right: T?): T? {
		if (left == null) return right
		if (right == null) return left

		return operation(left, right)
	}

	private infix fun IntRange.outOf(other: IntRange) = first > other.last || last < other.first

	private infix fun IntRange.insideOf(other: IntRange) = other.first <= first && last <= other.last

	private fun IntRange.isCollapsed() = first == last

	private fun IntRange.mid() = first + (last - first) / 2

	private fun Int.left() = this * 2 + 1

	private fun Int.right() = this * 2 + 2
}

data class Node(val balancedBrackets: Int, val openBrackets: Int, val closeBrackets: Int)

private fun nodeCombiner(n1: Node, n2: Node): Node {
	val balancedBrackets = min(n1.openBrackets, n2.closeBrackets)

	return Node(
		n1.balancedBrackets + n2.balancedBrackets + balancedBrackets * 2,
		n1.openBrackets + n2.openBrackets - balancedBrackets,
		n1.closeBrackets + n2.closeBrackets - balancedBrackets
	)
}


import java.util.ArrayDeque

fun main() {
    val s = readLn()

    val tree = s.map { c ->
        if(c == '(') SegmentEntry(0, 1, 0)
        else SegmentEntry(0, 0, 1)
    }.toSegmentTree(SegmentEntry(0, 0, 0), SegmentEntry::plus)

    val m = readInt()

    output {
        repeat(m) {
            val (l, r) = readInts()
            val ans = tree[l - 1 until r].maxGood

            println(ans)
        }
    }
}

data class SegmentEntry(val maxGood: Int, val openRem: Int, val closeRem: Int) {
    operator fun plus(other: SegmentEntry): SegmentEntry {
        val satisfied = minOf(openRem, other.closeRem)
        return SegmentEntry(
            maxGood = maxGood + other.maxGood + satisfied * 2,
            openRem = openRem + other.openRem - satisfied,
            closeRem = closeRem + other.closeRem - satisfied
        )
    }
}

/** Segment tree can be built for any monoid (set with associative binary operation and identity element) */
fun <T> Collection<T>.toSegmentTree(
    identityValue: T, combiner: (T, T) -> T
): SegmentTree<T> = SegmentTree(size, identityValue, combiner).also { it.copyFrom(this) }

class SegmentTree<T>(
    val size: Int,
    val identityValue: T,
    val combiner: (T, T) -> T) {

    @Suppress("UNCHECKED_CAST")
    private val array = Array<Any?>(2 * size) { identityValue } as Array<T>

    val lastIndex get() = size - 1
    val indices get() = 0 until size
    val asList: List<T> by lazy {
        object : AbstractList<T>() {
            override val size: Int get() = this@SegmentTree.size
            override fun get(index: Int): T = this@SegmentTree[index]
        }
    }

    /** instantiates values from an iterable, O(n) time */
    fun copyFrom(iterable: Iterable<T>) {
        run {
            iterable.forEachIndexed { i, t ->
                if(i > lastIndex) return@run
                array[i + size] = t
            }
        }
        for(i in size-1 downTo 1) {
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Updates a value, O(log n) time */
    operator fun set(index: Int, value: T) {
        require(index in indices)
        var i = index + size
        array[i] = value
        while(true) {
            i = i shr 1
            if(i <= 0) break
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Gets a value by its index, O(1) time */
    operator fun get(index: Int): T {
        require(index in indices)
        return array[index + size]
    }

    /** gets the result of applying the monoid operation to the values in the range, O(log n) time */
    operator fun get(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        // two accumulators to support non-commutative monoids
        var lAcc = identityValue
        var rAcc = identityValue

        while(l < r) {
            if(l and 1 == 1) {
                lAcc = combiner(lAcc, array[l++])
            }
            if(r and 1 == 1) {
                rAcc = combiner(array[--r], rAcc)
            }

            l = l shr 1
            r = r shr 1
        }

        return combiner(lAcc, rAcc)
    }
}

fun readLn() = readLine()!!
fun readInt() = readLn().toInt()
fun readDouble() = readLn().toDouble()
fun readLong() = readLn().toLong()
fun readStrings() = readLn().split(' ')
fun readStringSeq() = readLn().splitToSequence(' ')
fun readInts() = readStrings().map { it.toInt() }
fun readIntSeq() = readStringSeq().map { it.toInt() }
fun readDoubles() = readStrings().map { it.toDouble() }
fun readDoubleSeq() = readStringSeq().map { it.toDouble() }
fun readLongs() = readStrings().map { it.toLong() }
fun readLongSeq() = readStringSeq().map { it.toLong() }

class Output {
    val outputSb = StringBuilder()
    fun print(o: Any?) { outputSb.append(o) }
    fun println() { outputSb.append('\n') }
    fun println(o: Any?) { outputSb.append(o).append('\n') }
    @JvmName("_print") fun Any?.print() = print(this)
    @JvmName("_println") fun Any?.println() = println(this)
    fun nowPrint() { kotlin.io.print(outputSb) }
}
inline fun output(block: Output.()->Unit) { Output().apply(block).nowPrint() }


import java.util.ArrayDeque

fun main() {
    val s = readLn()

    val tree = s.map { c ->
        if(c == '(') SegmentEntry(0, 1, 0)
        else SegmentEntry(0, 0, 1)
    }.toSegmentTree(SegmentEntry(0, 0, 0), SegmentEntry::plus, isCommutative = false)

    val m = readInt()

    output {
        repeat(m) {
            val (l, r) = readInts()
            val ans = tree[l - 1 until r].maxGood

            println(ans)
        }
    }
}

data class SegmentEntry(val maxGood: Int, val openRem: Int, val closeRem: Int) {
    operator fun plus(other: SegmentEntry): SegmentEntry {
        val satisfied = minOf(openRem, other.closeRem)
        return SegmentEntry(
            maxGood = maxGood + other.maxGood + satisfied * 2,
            openRem = openRem + other.openRem - satisfied,
            closeRem = closeRem + other.closeRem - satisfied
        )
    }
}

/** Segment tree can be built for any monoid (set with associative binary operation and identity element) */
fun <T> Collection<T>.toSegmentTree(
    identityValue: T, combiner: (T, T) -> T, isCommutative: Boolean = true
): SegmentTree<T> = SegmentTree(size, identityValue, combiner, isCommutative).also { it.copyFrom(this) }

class SegmentTree<T>(
    val size: Int,
    val identityValue: T,
    val combiner: (T, T) -> T,
    val isCommutative: Boolean = true) {

    @Suppress("UNCHECKED_CAST")
    private val array = Array<Any?>(2 * size) { identityValue } as Array<T>

    val lastIndex get() = size - 1
    val indices get() = 0 until size
    val asList: List<T> by lazy {
        object : AbstractList<T>() {
            override val size: Int get() = this@SegmentTree.size
            override fun get(index: Int): T = this@SegmentTree[index]
        }
    }

    /** instantiates values from an iterable, O(n) time */
    fun copyFrom(iterable: Iterable<T>) {
        run {
            iterable.forEachIndexed { i, t ->
                if(i > lastIndex) return@run
                array[i + size] = t
            }
        }
        for(i in size-1 downTo 1) {
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Updates a value, O(log n) time */
    operator fun set(index: Int, value: T) {
        require(index in indices)
        var i = index + size
        array[i] = value
        while(true) {
            i = i shr 1
            if(i <= 0) break
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Gets a value by its index, O(1) time */
    operator fun get(index: Int): T {
        require(index in indices)
        return array[index + size]
    }

    /** gets the result of applying the monoid operation to the values in the range, O(log n) time */
    operator fun get(range: IntRange) = if(isCommutative) getCommutative(range) else getNonCommutative(range)

    private fun getCommutative(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        var ans = identityValue

        while(l < r) {
            if(l and 1 == 1) {
                ans = combiner(array[l++], ans)
            }
            if(r and 1 == 1) {
                ans = combiner(array[--r], ans)
            }

            l = l shr 1
            r = r shr 1
        }

        return ans
    }

    private fun getNonCommutative(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        var ans = identityValue

        val lDeq = mutableListOf<T>()
        val rDeq = mutableListOf<T>()

        while(l < r) {
            if(l and 1 == 1) {
                lDeq.add(array[l++])
            }
            if(r and 1 == 1) {
                rDeq.add(array[--r])
            }

            l = l shr 1
            r = r shr 1
        }

        ans = lDeq.fold(ans, combiner)
        ans = rDeq.asReversed().fold(ans, combiner)

        return ans
    }
}

fun readLn() = readLine()!!
fun readInt() = readLn().toInt()
fun readDouble() = readLn().toDouble()
fun readLong() = readLn().toLong()
fun readStrings() = readLn().split(' ')
fun readStringSeq() = readLn().splitToSequence(' ')
fun readInts() = readStrings().map { it.toInt() }
fun readIntSeq() = readStringSeq().map { it.toInt() }
fun readDoubles() = readStrings().map { it.toDouble() }
fun readDoubleSeq() = readStringSeq().map { it.toDouble() }
fun readLongs() = readStrings().map { it.toLong() }
fun readLongSeq() = readStringSeq().map { it.toLong() }

class Output {
    val outputSb = StringBuilder()
    fun print(o: Any?) { outputSb.append(o) }
    fun println() { outputSb.append('\n') }
    fun println(o: Any?) { outputSb.append(o).append('\n') }
    @JvmName("_print") fun Any?.print() = print(this)
    @JvmName("_println") fun Any?.println() = println(this)
    fun nowPrint() { kotlin.io.print(outputSb) }
}
inline fun output(block: Output.()->Unit) { Output().apply(block).nowPrint() }


fun main() {
    val s = readLn()

    val LEFT = SegmentEntry(0, 1, 0)
    val RIGHT = SegmentEntry(0, 0, 1)
    val ZERO = SegmentEntry(0, 0, 0)

    val tree = s.map { c ->
        if(c == '(') LEFT
        else RIGHT
    }.toSegmentTree(ZERO, SegmentEntry::plus)

    val m = readInt()

    output {
        repeat(m) {
            val (l, r) = readInts()
            val ans = tree[l - 1 until r].maxGood

            println(ans)
        }
    }
}

data class SegmentEntry(val maxGood: Int, val openRem: Int, val closeRem: Int) {
    operator fun plus(other: SegmentEntry): SegmentEntry {
        val satisfied = minOf(openRem, other.closeRem)
        return SegmentEntry(
            maxGood = maxGood + other.maxGood + satisfied * 2,
            openRem = openRem + other.openRem - satisfied,
            closeRem = closeRem + other.closeRem - satisfied
        )
    }
}

/** Segment tree can be built for any monoid (set with associative binary operation and identity element) */
fun <T> Collection<T>.toSegmentTree(
    identityValue: T, combiner: (T, T) -> T
): SegmentTree<T> = SegmentTree(size, identityValue, combiner).also { it.copyFrom(this) }

class SegmentTree<T>(
    val size: Int,
    val identityValue: T,
    val combiner: (T, T) -> T) {

    @Suppress("UNCHECKED_CAST")
    private val array = Array<Any?>(2 * size) { identityValue } as Array<T>

    val lastIndex get() = size - 1
    val indices get() = 0 until size
    val asList: List<T> by lazy {
        object : AbstractList<T>() {
            override val size: Int get() = this@SegmentTree.size
            override fun get(index: Int): T = this@SegmentTree[index]
        }
    }

    /** instantiates values from an iterable, O(n) time */
    fun copyFrom(iterable: Iterable<T>) {
        run {
            iterable.forEachIndexed { i, t ->
                if(i > lastIndex) return@run
                array[i + size] = t
            }
        }
        for(i in size-1 downTo 1) {
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Updates a value, O(log n) time */
    operator fun set(index: Int, value: T) {
        require(index in indices)
        var i = index + size
        array[i] = value
        while(true) {
            i = i shr 1
            if(i <= 0) break
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Gets a value by its index, O(1) time */
    operator fun get(index: Int): T {
        require(index in indices)
        return array[index + size]
    }

    /** gets the result of applying the monoid operation to the values in the range, O(log n) time */
    operator fun get(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        // two accumulators to support non-commutative monoids
        var lAcc = identityValue
        var rAcc = identityValue

        while(l < r) {
            if(l and 1 == 1) {
                lAcc = combiner(lAcc, array[l++])
            }
            if(r and 1 == 1) {
                rAcc = combiner(array[--r], rAcc)
            }

            l = l shr 1
            r = r shr 1
        }

        return combiner(lAcc, rAcc)
    }
}

fun readLn() = readLine()!!
fun readInt() = readLn().toInt()
fun readDouble() = readLn().toDouble()
fun readLong() = readLn().toLong()
fun readStrings() = readLn().split(' ')
fun readStringSeq() = readLn().splitToSequence(' ')
fun readInts() = readStrings().map { it.toInt() }
fun readIntSeq() = readStringSeq().map { it.toInt() }
fun readDoubles() = readStrings().map { it.toDouble() }
fun readDoubleSeq() = readStringSeq().map { it.toDouble() }
fun readLongs() = readStrings().map { it.toLong() }
fun readLongSeq() = readStringSeq().map { it.toLong() }

class Output {
    val outputSb = StringBuilder()
    fun print(o: Any?) { outputSb.append(o) }
    fun println() { outputSb.append('\n') }
    fun println(o: Any?) { outputSb.append(o).append('\n') }
    @JvmName("_print") fun Any?.print() = print(this)
    @JvmName("_println") fun Any?.println() = println(this)
    fun nowPrint() { kotlin.io.print(outputSb) }
}
inline fun output(block: Output.()->Unit) { Output().apply(block).nowPrint() }


import java.util.ArrayDeque

fun main() {
    val s = readLn()

    val tree = s.map { c ->
        if(c == '(') SegmentEntry(0, 1, 0)
        else SegmentEntry(0, 0, 1)
    }.toSegmentTree(SegmentEntry(0, 0, 0), SegmentEntry::plus)

    val m = readInt()

    output {
        repeat(m) {
            val (l, r) = readInts()
            val ans = tree[l - 1 until r].maxGood

            println(ans)
        }
    }
}

data class SegmentEntry(val maxGood: Int, val openRem: Int, val closeRem: Int) {
    operator fun plus(other: SegmentEntry): SegmentEntry {
        val satisfied = minOf(openRem, other.closeRem)
        return SegmentEntry(
            maxGood = maxGood + other.maxGood + satisfied * 2,
            openRem = openRem + other.openRem - satisfied,
            closeRem = closeRem + other.closeRem - satisfied
        )
    }
}

/** Segment tree can be built for any monoid (set with associative binary operation and identity element) */
fun <T> Collection<T>.toSegmentTree(identityValue: T, combiner: (T, T) -> T): SegmentTree<T> =
    SegmentTree(size, identityValue, combiner).also { it.copyFrom(this) }

class SegmentTree<T>(
    val size: Int,
    val identityValue: T,
    val combiner: (T, T) -> T) {

    @Suppress("UNCHECKED_CAST")
    private val array = Array<Any?>(2 * size) { identityValue } as Array<T>

    val lastIndex get() = size - 1
    val indices get() = 0 until size
    val asList: List<T> by lazy {
        object : AbstractList<T>() {
            override val size: Int get() = this@SegmentTree.size
            override fun get(index: Int): T = this@SegmentTree[index]
        }
    }

    /** instantiates values from an iterable, O(n) time */
    fun copyFrom(iterable: Iterable<T>) {
        run {
            iterable.forEachIndexed { i, t ->
                if(i > lastIndex) return@run
                array[i + size] = t
            }
        }
        for(i in size-1 downTo 1) {
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Updates a value, O(log n) time */
    operator fun set(index: Int, value: T) {
        require(index in indices)
        var i = index + size
        array[i] = value
        while(true) {
            i = i shr 1
            if(i <= 0) break
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Gets a value by its index, O(1) time */
    operator fun get(index: Int): T {
        require(index in indices)
        return array[index + size]
    }

    /** gets the result of applying the monoid operation to the values in the range, O(log n) time */
    operator fun get(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        var ans = identityValue

        val lDeq = mutableListOf<T>()
        val rDeq = mutableListOf<T>()

        while(l < r) {
            if(l and 1 == 1) {
                lDeq.add(array[l++])
            }
            if(r and 1 == 1) {
                rDeq.add(array[--r])
            }

            l = l shr 1
            r = r shr 1
        }

        ans = lDeq.fold(ans, combiner)
        ans = rDeq.asReversed().fold(ans, combiner)

        return ans
    }
}

fun readLn() = readLine()!!
fun readInt() = readLn().toInt()
fun readDouble() = readLn().toDouble()
fun readLong() = readLn().toLong()
fun readStrings() = readLn().split(' ')
fun readStringSeq() = readLn().splitToSequence(' ')
fun readInts() = readStrings().map { it.toInt() }
fun readIntSeq() = readStringSeq().map { it.toInt() }
fun readDoubles() = readStrings().map { it.toDouble() }
fun readDoubleSeq() = readStringSeq().map { it.toDouble() }
fun readLongs() = readStrings().map { it.toLong() }
fun readLongSeq() = readStringSeq().map { it.toLong() }

class Output {
    val outputSb = StringBuilder()
    fun print(o: Any?) { outputSb.append(o) }
    fun println() { outputSb.append('\n') }
    fun println(o: Any?) { outputSb.append(o).append('\n') }
    @JvmName("_print") fun Any?.print() = print(this)
    @JvmName("_println") fun Any?.println() = println(this)
    fun nowPrint() { kotlin.io.print(outputSb) }
}
inline fun output(block: Output.()->Unit) { Output().apply(block).nowPrint() }


import java.util.ArrayDeque

fun main() {
    val s = readLn()

    val tree = s.map { c ->
        if(c == '(') SegmentEntry(0, 1, 0)
        else SegmentEntry(0, 0, 1)
    }.toSegmentTree(SegmentEntry(0, 0, 0), SegmentEntry::plus)

    val m = readInt()

    output {
        repeat(m) {
            val (l, r) = readInts()
            val ans = tree[l - 1 until r].maxGood

            println(ans)
        }
    }
}

data class SegmentEntry(val maxGood: Int, val openRem: Int, val closeRem: Int) {
    operator fun plus(other: SegmentEntry): SegmentEntry {
        val satisfied = minOf(openRem, other.closeRem)
        return SegmentEntry(
            maxGood = maxGood + other.maxGood + satisfied * 2,
            openRem = openRem + other.openRem - satisfied,
            closeRem = closeRem + other.closeRem - satisfied
        )
    }
}

/** Segment tree can be built for any monoid (set with associative binary operation and identity element) */
fun <T> Collection<T>.toSegmentTree(identityValue: T, combiner: (T, T) -> T): SegmentTree<T> =
    SegmentTree(size, identityValue, combiner).also { it.copyFrom(this) }

class SegmentTree<T>(
    val size: Int,
    val identityValue: T,
    val combiner: (T, T) -> T) {

    @Suppress("UNCHECKED_CAST")
    private val array = Array<Any?>(2 * size) { identityValue } as Array<T>

    val lastIndex get() = size - 1
    val indices get() = 0 until size
    val asList: List<T> by lazy {
        object : AbstractList<T>() {
            override val size: Int get() = this@SegmentTree.size
            override fun get(index: Int): T = this@SegmentTree[index]
        }
    }

    /** instantiates values from an iterable, O(n) time */
    fun copyFrom(iterable: Iterable<T>) {
        run {
            iterable.forEachIndexed { i, t ->
                if(i > lastIndex) return@run
                array[i + size] = t
            }
        }
        for(i in size-1 downTo 1) {
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Updates a value, O(log n) time */
    operator fun set(index: Int, value: T) {
        require(index in indices)
        var i = index + size
        array[i] = value
        while(true) {
            i = i shr 1
            if(i <= 0) break
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Gets a value by its index, O(1) time */
    operator fun get(index: Int): T {
        require(index in indices)
        return array[index + size]
    }

    /** gets the result of applying the monoid operation to the values in the range, O(log n) time */
    operator fun get(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        var ans = identityValue

        val lDeq = ArrayDeque<T>()
        val rDeq = ArrayDeque<T>()

        while(l < r) {
            if(l and 1 == 1) {
                lDeq.add(array[l++])
            }
            if(r and 1 == 1) {
                rDeq.push(array[--r])
            }

            l = l shr 1
            r = r shr 1
        }

        ans = lDeq.fold(ans, combiner)
        ans = rDeq.fold(ans, combiner)

        return ans
    }
}

fun readLn() = readLine()!!
fun readInt() = readLn().toInt()
fun readDouble() = readLn().toDouble()
fun readLong() = readLn().toLong()
fun readStrings() = readLn().split(' ')
fun readStringSeq() = readLn().splitToSequence(' ')
fun readInts() = readStrings().map { it.toInt() }
fun readIntSeq() = readStringSeq().map { it.toInt() }
fun readDoubles() = readStrings().map { it.toDouble() }
fun readDoubleSeq() = readStringSeq().map { it.toDouble() }
fun readLongs() = readStrings().map { it.toLong() }
fun readLongSeq() = readStringSeq().map { it.toLong() }

class Output {
    val outputSb = StringBuilder()
    fun print(o: Any?) { outputSb.append(o) }
    fun println() { outputSb.append('\n') }
    fun println(o: Any?) { outputSb.append(o).append('\n') }
    @JvmName("_print") fun Any?.print() = print(this)
    @JvmName("_println") fun Any?.println() = println(this)
    fun nowPrint() { kotlin.io.print(outputSb) }
}
inline fun output(block: Output.()->Unit) { Output().apply(block).nowPrint() }


import java.util.ArrayDeque

fun main() {
    val s = readLn()

    val tree = s.map { c ->
        if(c == '(') SegmentEntry(0, 1, 0)
        else SegmentEntry(0, 0, 1)
    }.toSegmentTree(SegmentEntry(0, 0, 0), SegmentEntry::plus, isCommutative = false)

    val m = readInt()

    output {
        repeat(m) {
            val (l, r) = readInts()
            val ans = tree[l - 1 until r].maxGood

            println(ans)
        }
    }
}

data class SegmentEntry(val maxGood: Int, val openRem: Int, val closeRem: Int) {
    operator fun plus(other: SegmentEntry): SegmentEntry {
        val satisfied = minOf(openRem, other.closeRem)
        return SegmentEntry(
            maxGood = maxGood + other.maxGood + satisfied * 2,
            openRem = openRem + other.openRem - satisfied,
            closeRem = closeRem + other.closeRem - satisfied
        )
    }
}

/** Segment tree can be built for any monoid (set with associative binary operation and identity element) */
fun <T> Collection<T>.toSegmentTree(
    identityValue: T, combiner: (T, T) -> T, isCommutative: Boolean = true
): SegmentTree<T> = SegmentTree(size, identityValue, combiner, isCommutative).also { it.copyFrom(this) }

class SegmentTree<T>(
    val size: Int,
    val identityValue: T,
    val combiner: (T, T) -> T,
    val isCommutative: Boolean = true) {

    @Suppress("UNCHECKED_CAST")
    private val array = Array<Any?>(2 * size) { identityValue } as Array<T>

    val lastIndex get() = size - 1
    val indices get() = 0 until size
    val asList: List<T> by lazy {
        object : AbstractList<T>() {
            override val size: Int get() = this@SegmentTree.size
            override fun get(index: Int): T = this@SegmentTree[index]
        }
    }

    /** instantiates values from an iterable, O(n) time */
    fun copyFrom(iterable: Iterable<T>) {
        run {
            iterable.forEachIndexed { i, t ->
                if(i > lastIndex) return@run
                array[i + size] = t
            }
        }
        for(i in size-1 downTo 1) {
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Updates a value, O(log n) time */
    operator fun set(index: Int, value: T) {
        require(index in indices)
        var i = index + size
        array[i] = value
        while(true) {
            i = i shr 1
            if(i <= 0) break
            array[i] = combiner(array[i*2], array[i*2+1])
        }
    }

    /** Gets a value by its index, O(1) time */
    operator fun get(index: Int): T {
        require(index in indices)
        return array[index + size]
    }

    /** gets the result of applying the monoid operation to the values in the range, O(log n) time */
    operator fun get(range: IntRange): T {
        if(range.isEmpty()) return identityValue
        require(range.first in indices)
        require(range.endInclusive in indices)
        var l = range.first + size
        var r = range.endInclusive + size + 1

        var ans = identityValue

        if(isCommutative) {
            while (l < r) {
                if (l and 1 == 1) {
                    ans = combiner(array[l++], ans)
                }
                if (r and 1 == 1) {
                    ans = combiner(array[--r], ans)
                }

                l = l shr 1
                r = r shr 1
            }
        } else {
            val lDeq = mutableListOf<T>()
            val rDeq = mutableListOf<T>()

            while(l < r) {
                if(l and 1 == 1) {
                    lDeq.add(array[l++])
                }
                if(r and 1 == 1) {
                    rDeq.add(array[--r])
                }

                l = l shr 1
                r = r shr 1
            }

            ans = lDeq.fold(ans, combiner)
            ans = rDeq.asReversed().fold(ans, combiner)
        }

        return ans
    }
}

fun readLn() = readLine()!!
fun readInt() = readLn().toInt()
fun readDouble() = readLn().toDouble()
fun readLong() = readLn().toLong()
fun readStrings() = readLn().split(' ')
fun readStringSeq() = readLn().splitToSequence(' ')
fun readInts() = readStrings().map { it.toInt() }
fun readIntSeq() = readStringSeq().map { it.toInt() }
fun readDoubles() = readStrings().map { it.toDouble() }
fun readDoubleSeq() = readStringSeq().map { it.toDouble() }
fun readLongs() = readStrings().map { it.toLong() }
fun readLongSeq() = readStringSeq().map { it.toLong() }

class Output {
    val outputSb = StringBuilder()
    fun print(o: Any?) { outputSb.append(o) }
    fun println() { outputSb.append('\n') }
    fun println(o: Any?) { outputSb.append(o).append('\n') }
    @JvmName("_print") fun Any?.print() = print(this)
    @JvmName("_println") fun Any?.println() = println(this)
    fun nowPrint() { kotlin.io.print(outputSb) }
}
inline fun output(block: Output.()->Unit) { Output().apply(block).nowPrint() }