12 12
5 1
5 11
1 11
8 11
8 9
5 12
6 9
7 11
9 3
9 10
4 12
10 2
78
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
2 2
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 12
3 3
3 4
3 5
3 6
3 7
3 8
3 9
3 10
3 11
3 12
4 4
4 5
4 6
4 7
4 8
4 9
4 10
4 11
4 12
5 5
5 6
5 7
5 8
5 9
5 10
5 11
5 12
6 6
6 7
6 8
6 9
6 10
6 11
6 12
7 7
7 8
7 9
7 10
7 11
7 12
8 8
8 9
8 10
8 11
8 12
9 9
9 10
9 11
9 12
10 10
10 11
10 12
11 11
11 12
12 12

1
3
6
10
15
21
28
36
45
55
65
76
1
3
6
10
15
21
28
36
45
55
66
1
3
6
10
15
21
28
36
45
55
1
3
6
10
15
21
28
36
45
1
3
6
10
15
21
28
36
1
3
6
10
15
21
28
1
3
6
10
15
21
1
3
6
10
15
1
3
6
10
1
3
6
1
3
1

//package codeforces.R453;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class C
{
	static TreeMap<Integer, Integer> map;
	static int n, m, vid;
	static ArrayList<Integer>[] adj;
	static int[] f, cycle, vis, depth;
	static long[] set; static int sInd;
	
	public static void main(String[] args) throws IOException
	{
		Scanner sc = new Scanner(System.in);
		PrintWriter pw = new PrintWriter(System.out);
		
		n = sc.nextInt();
		m = sc.nextInt();
		
		set = new long[m];
		f = new int[n];
		cycle = new int[n];
		vis = new int[n];
		vid++;
		adj = new ArrayList[n];
		depth = new int[n];
		for (int i = 0; i < adj.length; i++)
			adj[i] = new ArrayList<Integer>();
		
		for (int i = 0; i < m; i++)
		{
			int a = sc.nextInt()-1;
			int b = sc.nextInt()-1;
			adj[a].add(b);
			adj[b].add(a);
		}
		
		
		dfs(0,-1,1);
		
		Arrays.sort(set);
		
		vid++;
		for (int i = 0; i < n; i++)
		{
			if(vis[i] != vid)
			{
				mx = i;
				maxCycle(i);
				if(mx == i)
					cycle[i] = n-1;
				else
					cycle[i] = mx-1;
			}
			else
			{
				cycle[i] = n-1;
			}
		}
		
		buildF();
		
		int q = sc.nextInt();
		
		int N = 1; while(N < n) N <<= 1; //padding
		
		int[] in = new int[N + 1];
		
		SegmentTree tree = new SegmentTree(in);
		
		int[][][] queries = new int[n][2][];
		int[] ql = new int[q];
		int[] qr = new int[q];
		int[] cnt = new int[n];
		long[] ans = new long[q];
		for (int i = 0; i < q; i++)
		{
			int l = sc.nextInt()-1;
			ql[i] = l;
			qr[i] = sc.nextInt()-1;
			cnt[l]++;
		}
		for (int i = 0; i < n; i++)
		{
			queries[i][0] = new int[cnt[i]];
			queries[i][1] = new int[cnt[i]--];
		}
		
		for (int i = 0; i < q; i++)
		{
			int l = ql[i];
			int r = qr[i];
			queries[l][0][cnt[l]] = r;
			queries[l][1][cnt[l]--] = i;
		}
		
		for (int i = n-1; i >= 0; i--)
		{
			tree.update_range(i+1, f[i]+1, 1);
			int ll = queries[i][0].length;
			for (int j = 0; j < ll; j++)
			{
				int r = queries[i][0][j];
				int ind = queries[i][1][j];
				ans[ind] = tree.query(i+1, r+1);
			}
		}
		
		for (int i = 0; i < q; i++)
			pw.println(ans[i]);
		
		pw.flush();
		pw.close();
	}
	
	static void add(int i)
	{
		map.put(i, map.getOrDefault(i, 0)+1);
	}
	
	static void remove(int i)
	{
		int v = map.remove(i);
		if(v == 1)
			return;
		map.put(i, v-1);
	}
	
	private static void buildF()
	{
//		TreeSet<Pair> s = new TreeSet<C.Pair>();
		map = new TreeMap<Integer, Integer>();
		int l = 0, r = 1;
//		s.add(new Pair(cycle[0], 0));
		add(cycle[0]);
		for (; l < n; l++)
		{
			while(r < n && r <= map.firstKey())
			{
//				map.add(new Pair(cycle[r], r));
				add(cycle[r]);
				r++;
			}
			f[l] = r-1;
//			s.remove(new Pair(cycle[l], l));
			remove(cycle[l]);
		}
	}
	
	static class Pair implements Comparable<Pair>
	{
		int v, ind;

		public Pair(int v, int ind)
		{
			this.v = v;
			this.ind = ind;
		}

		@Override
		public int compareTo(Pair p)
		{
			if(v != p.v)
				return v - p.v;
			return ind - p.ind;
		}
	}

	private static int dfs(int u, int p, int d)
	{
		vis[u] = vid;
		depth[u] = d;
		int min = d;
		for (int v : adj[u])
		{
			if(vis[v] != vid)
			{
				int mn = dfs(v, u, d+1);
				if(min > mn)
					min = mn;
				if(mn > d)
				{
					set[sInd++] = wrap(v, u);
				}
			}else
			{
				if(v != p)
					min = Math.min(min, depth[v]);
			}
		}
		return min;
	}

	static int mx;
	static void maxCycle(int u)
	{
		vis[u] = vid;
		mx = Math.max(mx, u);
		for (int v : adj[u])
		{
			if(vis[v] != vid && Arrays.binarySearch(set, wrap(u, v)) < 0)
			{
				maxCycle(v);
			}
		}
	}
	
	static long wrap(int a, int b)
	{
		return (1l*Math.min(a, b) << 31) + Math.max(a, b);
	}
	
	static class SegmentTree
	{
		int N; 			//the number of elements in the array as a power of 2 (i.e. after padding)
		int[] array;
		long[] sTree, lazy;
		
		SegmentTree(int[] in)		
		{
			array = in; N = in.length - 1;
			sTree = new long[N<<1];		//no. of nodes = 2*N - 1, we add one to cross out index zero
			lazy = new long[N<<1];
			build(1,1,N);
		}
		
		void build(int node, int b, int e)	// O(n)
		{
			if(b == e)					
				sTree[node] = array[b];	// modify base case
			else						
			{
				int mid = b + e >> 1;
				build(node<<1,b,mid);
				build(node<<1|1,mid+1,e);
				sTree[node] = sTree[node<<1]+sTree[node<<1|1];	// modify merging
			}
		}
		
		
		void update_point(int index, int val)			// O(log n)
		{
			index += N - 1;				
			sTree[index] += val;	// base case		
			while(index>1)				
			{
				index >>= 1;
				sTree[index] = sTree[index<<1] + sTree[index<<1|1];		// merging
			}
		}
		
		
		void update_range(int i, int j, int val)		// O(log n) 
		{
			update_range(1,1,N,i,j,val);
		}
		
		void update_range(int node, int b, int e, int i, int j, int val)
		{
			if(i > e || j < b)		
				return;
			if(b >= i && e <= j)		
			{
				sTree[node] += (e-b+1)*val;			// how value node carrying is modified
				lazy[node] += val;			// lazy value for node
			}							
			else		
			{
				int mid = b + e >> 1;
				propagate(node, b, mid, e);
				update_range(node<<1,b,mid,i,j,val);
				update_range(node<<1|1,mid+1,e,i,j,val);
				sTree[node] = sTree[node<<1] + sTree[node<<1|1];		// merging
			}
			
		}
		
		// modify
		void propagate(int node, int b, int mid, int e)		
		{
			lazy[node<<1] += lazy[node];
			lazy[node<<1|1] += lazy[node];
			sTree[node<<1] += (mid-b+1)*lazy[node];		
			sTree[node<<1|1] += (e-mid)*lazy[node];		
			lazy[node] = 0;
		}
		
		long query(int i, int j)
		{
			return query(1,1,N,i,j);
		}
		
		long query(int node, int b, int e, int i, int j)	// O(log n)
		{
			if(i>e || j <b)
				return 0;		// base case 1
			if(b>= i && e <= j)
				return sTree[node];	// base case 2
			int mid = b + e >> 1;
			propagate(node, b, mid, e);
			long q1 = query(node<<1,b,mid,i,j);
			long q2 = query(node<<1|1,mid+1,e,i,j);
			return q1 + q2;	// merging
					
		}
	}

	
	
	
	
	
	
	static class Scanner
	{
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s)
		{
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException
		{
			br = new BufferedReader(new FileReader(new File((s))));
		}

		public String next() throws IOException
		{
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException
		{
			return Integer.parseInt(next());
		}

		public long nextLong() throws IOException
		{
			return Long.parseLong(next());
		}

		public String nextLine() throws IOException
		{
			return br.readLine();
		}

		public double nextDouble() throws IOException
		{
			String x = next();
			StringBuilder sb = new StringBuilder("0");
			double res = 0, f = 1;
			boolean dec = false, neg = false;
			int start = 0;
			if (x.charAt(0) == '-')
			{
				neg = true;
				start++;
			}
			for (int i = start; i < x.length(); i++)
				if (x.charAt(i) == '.')
				{
					res = Long.parseLong(sb.toString());
					sb = new StringBuilder("0");
					dec = true;
				} else
				{
					sb.append(x.charAt(i));
					if (dec)
						f *= 10;
				}
			res += Long.parseLong(sb.toString()) / f;
			return res * (neg ? -1 : 1);
		}

		public boolean ready() throws IOException
		{
			return br.ready();
		}
	}
}
