#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		map<int, vector<int> > areSame;
		for (int i=0;i<n;i++) {
			z.t[0][i] += n; z.t[1][i] += n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) areSame[z.t[0][i]].pb(y.t[1][i]);
		}
		map<int, int> labels;
		for (auto p: areSame)
			if (p.S.size() == 1) labels[p.F] = p.S[0];
			else for (auto v: p.S) labels[v] = p.F;

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				if (labels.count(x.t[j][i])) x.t[j][i] = labels[x.t[j][i]];
		x.sz = y.sz + z.sz - labels.size();
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[40], vis[40];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
} t[4*N];

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

// int parent(int u) {
// 	return par[u] == u ? u : par[u] = parent(par[u]);
// }

// void combine (node &x, node &y, node &z, int mid) {
// 	if (y.sz == 0) x = z;
// 	else if (z.sz == 0) x = y;
// 	else {
// 		x.sz = y.sz + z.sz;
// 		for (int i=0;i<4*n;i++) par[i] = i, vis[i] = 0;
// 		for (int i=0;i<n;i++) {
// 			z.t[0][i] += 2*n; z.t[1][i] += 2*n;
// 			x.t[0][i] = y.t[0][i];
// 			x.t[1][i] = z.t[1][i];
// 			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
// 				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
// 			}
// 		}

// 		for (int i=0;i<n;i++)
// 			for (int j=0;j<2;j++) {
// 				x.t[j][i] = parent(x.t[j][i]);
// 				vis[x.t[j][i]] = 1;
// 			}
// 		for (int i=0,cnt=0;i<4*n;i++) if (vis[i]) par[i] = cnt++;
// 		for (int i=0;i<n;i++)
// 			for (int j=0;j<2;j++) {
// 				x.t[j][i] = par[(x.t[j][i])];
// 			}
// 	}
// }

void compress (node &x) {
	for (int i=0;i<4*n;i++) par[i] = 0;
	int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) par[x.t[i][j]] = 1;
	for (int i=1;i<4*n;i++) par[i] += par[i-1];
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = par[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<4*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += 2*n; z.t[1][i] += 2*n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}

void init (int k, int l, int r) {
	if (l == r) {
		uno(t[k], l);
	}
	else {
		int mid = (l+r)>>1;
		init (k<<1, l, mid);
		init (k<<1|1, mid+1, r);
		combine(t[k], t[k<<1], t[k<<1|1], mid);
	}
	// cout << "Init: " << l << " " << r << ": " << endl;
	// print(t[k]); cout << endl;
}

node _query(int k, int l, int r, int x, int y) {
// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
    node ret;
    if(l > y || r < x) {
    	return ret;
        // ret = 0; // return identity here
    }
    else if(l >= x && r <= y) {
        ret = t[k];
    } else {
	    int mid = (l+r)>>1;
	    // replace max with your function
	    node left = _query(k<<1, l, mid, x, y), right = _query(k<<1|1, mid+1, r, x, y);
	    combine(ret, left, right, mid);
    }
    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
    // print(ret); cout <<  endl;
    return ret;
}

int main(){
	// ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q;
	scanf("%d %d %d", &n, &m, &q);
	// n = 10; m = q = 1e5;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) {
			scanf("%d", &b[i][j]);
			// b[i][j] = rand()%m + 1;
		}
	init(1,0,m-1);
	while (q--) {
		int l, r;
		scanf("%d %d", &l, &r);
		// l = rand()%m + 1, r = rand()%m + 1;
		// if (l > r) swap(l, r);

		l--; r--;
		printf("%d\n", _query(1,0,m-1,l,r).sz);
	}
	return 0;
}


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

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == 0 || b[i][l] != b[i-1][l]) x.sz++;
	}
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		map<int, int> areSame;
		for (int i=0;i<n;i++) {
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) areSame[z.t[0][i]] = y.t[0][i];
		}
		for (int i=0;i<n;i++)
			if (areSame.count(x.t[1][i])) x.t[1][i] = areSame[x.t[1][i]];
		x.sz = y.sz + z.sz - areSame.size();
	}
}

node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << t[k] << endl;
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << ret << endl;
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		return _query(1,0,n-1,l,r).sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[20];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<2*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += n; z.t[1][i] += n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[z.t[0][i]] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[20];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<2*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += n; z.t[1][i] += n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[40];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<4*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += 2*n; z.t[1][i] += 2*n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
namespace segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	void segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}

	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	// ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; scanf("%d %d %d", &n, &m, &q);
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) scanf("%d", &b[i][j]);
	segtree::segtree(m);
	while (q--) {
		int l, r; scanf("%d %d", &l, &r); l--; r--;
		printf("%d\n", segtree::query(l,r));
	}
	return 0;
}


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

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5, inf = 2e9; // N -> max size of base array
int n, m, b[11][N];
inline bool valid (int x, int l, int r) {
	return l <= x && x <= r;
}
int count(int x) {
	if (!valid(x, 0, m-1)) return 0;
	int ans = 0;
	for (int i=0;i<n;i++) if (i == 0 || b[i][x] != b[i-1][x]) ans++;
	// cout << "Count: " << x << ": " << ans << endl;
	return ans;
}
int common (int x, int y, int l, int r) {
	if (!valid(x, l, r) || !valid(y, l, r)) return 0;
	int ans = 0;
	for (int i=0;i<n;i++) if (b[i][x] == b[i][y]) ans++;
	// cout << "Common: " << x << " " << y << ": " << ans << endl;
	return ans;
}
struct segtree{ //max segtree
	int n, t[4*N];
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) t[k] = count(l);
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			t[k] = t[k<<1] + t[k<<1|1] - common(mid, mid+1, l, r);
		}
		// cout << "Init: " << l << " " << r << ": " << t[k] << endl;
	}
	int _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    int ret;
	    if(l > y || r < x) {
	        ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    ret = _query(k<<1, l, mid, x, y)
		    			+ _query(k<<1|1, mid+1, r, x, y) - common(mid, mid+1, x, y);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << ret << endl;
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		return _query(1,0,n-1,l,r);
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[40];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<2*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += n; z.t[1][i] += n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[40], vis[40];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
} t[4*N];

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	for (int i=0;i<4*n;i++) par[i] = 0;
	int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) par[x.t[i][j]] = 1;
	for (int i=1;i<4*n;i++) par[i] += par[i-1];
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = par[x.t[i][j]]-1;
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<4*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += 2*n; z.t[1][i] += 2*n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}

void init (int k, int l, int r) {
	if (l == r) {
		uno(t[k], l);
	}
	else {
		int mid = (l+r)>>1;
		init (k<<1, l, mid);
		init (k<<1|1, mid+1, r);
		combine(t[k], t[k<<1], t[k<<1|1], mid);
	}
	// cout << "Init: " << l << " " << r << ": " << endl;
	// print(t[k]); cout << endl;
}

node _query(int k, int l, int r, int x, int y) {
// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
    node ret;
    if(l > y || r < x) {
    	return ret;
        // ret = 0; // return identity here
    }
    else if(l >= x && r <= y) {
        ret = t[k];
    } else {
	    int mid = (l+r)>>1;
	    // replace max with your function
	    node left = _query(k<<1, l, mid, x, y), right = _query(k<<1|1, mid+1, r, x, y);
	    combine(ret, left, right, mid);
    }
    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
    // print(ret); cout <<  endl;
    return ret;
}

int main(){
	// ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q;
	scanf("%d %d %d", &n, &m, &q);
	// n = 10; m = q = 1e5;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) {
			scanf("%d", &b[i][j]);
			// b[i][j] = rand()%m + 1;
		}
	init(1,0,m-1);
	while (q--) {
		int l, r;
		scanf("%d %d", &l, &r);
		// l = rand()%m + 1, r = rand()%m + 1;
		// if (l > r) swap(l, r);

		l--; r--;
		printf("%d\n", _query(1,0,m-1,l,r).sz);
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[40];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<4*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += 2*n; z.t[1][i] += 2*n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define F first
#define S second
using namespace std;

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N], par[40];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		x.t[0][i] = x.t[1][i] = x.sz;
		if (i == n-1 || b[i][l] != b[i+1][l]) x.sz++;
	}
}

void compress (node &x) {
	map<int,int> rank; int cnt = 0;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) rank[x.t[i][j]] = 0;
	for (auto &p: rank) p.S = cnt++;
	for (int i=0;i<2;i++)
		for (int j=0;j<n;j++) x.t[i][j] = rank[x.t[i][j]];
}

int parent(int u) {
	return par[u] == u ? u : par[u] = parent(par[u]);
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		x.sz = y.sz + z.sz;
		for (int i=0;i<2*n;i++) par[i] = i;
		for (int i=0;i<n;i++) {
			z.t[0][i] += 2*n; z.t[1][i] += 2*n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) if (parent(z.t[0][i]) != parent(y.t[1][i])) {
				par[parent(z.t[0][i])] = parent(y.t[1][i]); x.sz--;
			}
		}

		for (int i=0;i<n;i++)
			for (int j=0;j<2;j++)
				x.t[j][i] = parent(x.t[j][i]);
		compress (x);
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


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

// Segment Tree
// Tested here: http://codeforces.com/contest/597/submission/14216114
const int N = 1e5+5; // N -> max size of base array
int n, m, b[10][N];

struct node {
	int t[2][10], sz;
	node (): sz(0) {};
};

void uno (node &x, int l) {
	x.sz = 0;
	for (int i=0;i<n;i++) {
		if (i == 0 || b[i][l] != b[i-1][l]) x.sz++;
		x.t[0][i] = x.t[1][i] = x.sz;
	}
}

void combine (node &x, node y, node z, int mid) {
	if (y.sz == 0) x = z;
	else if (z.sz == 0) x = y;
	else {
		map<int, int> areSame;
		for (int i=0;i<n;i++) {
			z.t[0][i] += n; z.t[1][i] += n;
			x.t[0][i] = y.t[0][i];
			x.t[1][i] = z.t[1][i];
			if (b[i][mid] == b[i][mid+1]) areSame[z.t[0][i]] = y.t[1][i];
		}
		for (int i=0;i<n;i++)
			if (areSame.count(x.t[1][i])) x.t[1][i] = areSame[x.t[1][i]];
		x.sz = y.sz + z.sz - areSame.size();
	}
}

void print (node &x) {
	cout << "S: " << x.sz << endl;
	for (int i=0;i<n;i++) cout << x.t[0][i] << " " << x.t[1][i] << endl;
}
node t[4*N];
struct segtree { //max segtree
	int n;
	// n -> size of base array, t[i] -> value of segtree nodes, d[i] -> lazy update
	segtree(int _n = 0){
		n = _n;
		// memset(t,0,sizeof(int)*4*n); // 0 -> default value
		init(1, 0, n-1);
	}
	void init (int k, int l, int r) {
		if (l == r) {
			uno(t[k], l);
		}
		else {
			int mid = (l+r)>>1;
			init (k<<1, l, mid);
			init (k<<1|1, mid+1, r);
			combine(t[k], t[k<<1], t[k<<1|1], mid);
		}
		// cout << "Init: " << l << " " << r << ": " << endl;
		// print(t[k]);
	}
	node _query(int k, int l, int r, int x, int y) {
	// k -> node number, [l,r] -> segtree interval, [x,y] -> query interval
	    node ret;
	    if(l > y || r < x) {
	        // ret = 0; // return identity here
	    }
	    else if(l >= x && r <= y) {
	        ret = t[k];
	    } else {
		    int mid = (l+r)>>1;
		    // replace max with your function
		    combine(ret, _query(k<<1, l, mid, x, y),
		    			_query(k<<1|1, mid+1, r, x, y), mid);
	    }
	    // cout << "Q: " << l << " " << r << " " << x << " " << y << ": " << endl;
	    // print(ret);
	    return ret;
	}
	int query(int l, int r){ // [l,r] -> query interval
		node ret = _query(1,0,n-1,l,r);
		return ret.sz;
	}
};
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int q; cin >> n >> m >> q;
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++) cin >> b[i][j];
	segtree s(m);
	while (q--) {
		int l, r; cin >> l >> r; l--; r--;
		cout << s.query(l,r) << "\n";
	}
	return 0;
}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

int n, m, q, use;
vector<vector<int>> v;

struct DS
{
	int n;
	vector<int> a;
	DS(int _n)
	{
		n = _n;
		a.resize(n);
		for (int i = 0; i < n; i++)
			a[i] = i;
	}
	int find(int x)
	{
		return a[x] == x ? x : a[x] = find(a[x]);
	}
	void join(int x, int y)
	{
		x = find(x);
		y = find(y);
		a[x] = y;
	}
};

struct Node
{
	int lc, rc;
	int com, l, r;
	int lcom[10], rcom[10];
	Node()
	{
		lc = rc = 0;
		com = 1;
		l = r = 0;
	}
} P[300000];

int reassign(int lind, int rind)
{
	Node &l = P[lind];
	Node &r = P[rind];
	int res = 0;
	map<pair<int, int>, int> M;
	int *arr[] = { l.rcom, r.lcom, l.lcom, r.rcom };
	for (int j = 0; j < 4; j++)
		for (int i = 0; i < n; i++)
		{
			int &x = arr[j][i];
			pair<int, int> pa = { (j & 1), x };
			if (M.find(pa) == M.end())
				M[pa], M[pa] = M.size() - 1;
			x = M[pa];
			if (j < 2)
				res = max(res, x);
		}
	return res + 1;
}

void merge(int pind, int lind, int rind)
{
	Node &p = P[pind];
	Node &l = P[lind];
	Node &r = P[rind];
	int cnt = reassign(lind, rind);
	DS ds(cnt);
	for (int i = 0; i < n; i++)
		if (v[l.r - 1][i] == v[r.l][i])
			ds.join(l.rcom[i], r.lcom[i]);
	p.lc = lind, p.rc = rind;
	p.com = l.com + r.com;
	p.l = l.l, p.r = r.r;
	for (int i = 0; i < n; i++)
		p.lcom[i] = l.lcom[i], p.rcom[i] = r.rcom[i];
	int *arr[] = { p.lcom, p.rcom };
	for (int j = 0; j < 2; j++)
		for (int i = 0; i < n; i++)
		{
			int &x = arr[j][i];
			if (x < cnt)
				x = ds.find(x);
		}
	for (int i = 0; i < cnt; i++)
		if (ds.find(i) != i)
			p.com--;
}

int query(int pind, int lb, int rb)
{
	Node &p = P[pind];
	if (p.l == lb && p.r == rb)
		return pind;
	Node &l = P[p.lc];
	Node &r = P[p.rc];
	if (l.r >= rb)
		return query(p.lc, lb, rb);
	if (r.l <= lb)
		return query(p.rc, lb, rb);
	int res = use++;
	int lt = query(p.lc, lb, l.r);
	use++;
	int rt = query(p.rc, r.l, rb);
	merge(res, lt, rt);
	use -= 2;
	return res;
}

int build(int l, int r, vector<vector<int>> &v)
{
	int resind = use++;
	Node &res = P[resind];
	res.l = l;
	res.r = r;
	if (r - l == 1)
	{
		for (int i = 0; i < n; i++)
		{
			res.lcom[i] = res.rcom[i] = res.com;
			if (i + 1 < n && v[l][i] != v[l][i + 1])
				res.com++;
		}
		return resind;
	}
	int m = (l + r) / 2;
	res.lc = build(l, m, v);
	res.rc = build(m, r, v);
	merge(resind, res.lc, res.rc);
	return resind;
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	v.assign(m, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf("%d", &v[j][i]);
	build(0, m, v);
	for (int l, r; q > 0; q--)
	{
		scanf("%d%d", &l, &r);
		l--;
		printf("%d\n", P[query(0, l, r)].com);
	}
}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

int n, m, q, M[80];
vector<vector<int>> v;

struct DS
{
	int n;
	vector<int> a;
	DS(int _n)
	{
		n = _n;
		a.resize(n);
		for (int i = 0; i < n; i++)
			a[i] = i;
	}
	int find(int x)
	{
		return a[x] == x ? x : a[x] = find(a[x]);
	}
	void join(int x, int y)
	{
		x = find(x);
		y = find(y);
		a[x] = y;
	}
};

struct Node
{
	Node *lc, *rc;
	int com, l, r;
	vector<int> lcom, rcom;
	Node()
	{
		lc = rc = NULL;
		com = 1;
		l = r = 0;
	}
} *root;

int reassign(Node *l, Node *r)
{
	for (int i = 0; i < 80; i++)
		M[i] = -1;
	int res = 0, tmp = 0;
	for (int &x : l->rcom)
	{
		int pa = x;
		if (M[pa] == -1)
			M[pa] = tmp++;
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : r->lcom)
	{
		int pa = 40 + x;
		if (M[pa] == -1)
			M[pa] = tmp++;
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : l->lcom)
	{
		int pa = x;
		if (M[pa] == -1)
			M[pa] = tmp++;
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : r->rcom)
	{
		int pa = 40 + x;
		if (M[pa] == -1)
			M[pa] = tmp++;
		x = M[pa];
		res = max(res, x);
	}
	return res + 1;
}

void merge(Node *p, Node *l, Node *r)
{
	int cnt = reassign(l, r);
	DS ds(cnt);
	for (int i = 0; i < n; i++)
		if (v[l->r - 1][i] == v[r->l][i])
			ds.join(l->rcom[i], r->lcom[i]);
	p->lc = l, p->rc = r;
	p->com = l->com + r->com;
	p->l = l->l, p->r = r->r;
	p->lcom = l->lcom, p->rcom = r->rcom;
	for (int &x : p->lcom)
		if (x < cnt)
			x = ds.find(x);
	for (int &x : p->rcom)
		if (x < cnt)
			x = ds.find(x);
	for (int i = 0; i < cnt; i++)
		if (ds.find(i) != i)
			p->com--;
}

Node query(Node *p, int l, int r)
{
	if (p->l == l && p->r == r)
		return *p;
	if (p->lc->r >= r)
		return query(p->lc, l, r);
	if (p->rc->l <= l)
		return query(p->rc, l, r);
	Node res, lt = query(p->lc, l, p->lc->r), rt = query(p->rc, p->rc->l, r);
	merge(&res, &lt, &rt);
	return res;
}

Node* build(int l, int r, vector<vector<int>> &v)
{
	Node *res = new Node;
	res->l = l;
	res->r = r;
	if (r - l == 1)
	{
		res->lcom.resize(n);
		res->rcom.resize(n);
		for (int i = 0; i < n; i++)
		{
			res->lcom[i] = res->rcom[i] = res->com;
			if (i + 1 < n && v[l][i] != v[l][i + 1])
				res->com++;
		}
		return res;
	}
	int m = (l + r) / 2;
	res->lc = build(l, m, v);
	res->rc = build(m, r, v);
	merge(res, res->lc, res->rc);
	return res;
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	v.assign(m, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf("%d", &v[j][i]);
	root = build(0, m, v);
	for (int l, r; q > 0; q--)
	{
		scanf("%d%d", &l, &r);
		l--;
		printf("%d\n", query(root, l, r).com);
	}
}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

int n, m, q, use, M[80];
vector<vector<int>> v;

struct DS
{
	int n;
	vector<int> a;
	DS(int _n)
	{
		n = _n;
		a.resize(n);
		for (int i = 0; i < n; i++)
			a[i] = i;
	}
	int find(int x)
	{
		return a[x] == x ? x : a[x] = find(a[x]);
	}
	void join(int x, int y)
	{
		x = find(x);
		y = find(y);
		a[x] = y;
	}
};

struct Node
{
	int lc, rc;
	int com, l, r;
	int lcom[10], rcom[10];
	Node()
	{
		lc = rc = 0;
		com = 1;
		l = r = 0;
	}
} P[300000];

int reassign(int lind, int rind)
{
	Node &l = P[lind];
	Node &r = P[rind];
	int *arr[] = { l.rcom, r.lcom, l.lcom, r.rcom };
	for (int i = 0; i < 80; i++)
		M[i] = -1;
	int res = 0, tmp = 0;
	for (int j = 0; j < 4; j++)
		for (int i = 0; i < n; i++)
		{
			int &x = arr[j][i];
			int ind = (j & 1) * 40 + x;
			if (M[ind] == -1)
				M[ind] = tmp++;
			x = M[ind];
			if (j < 2)
				res = max(res, x);
		}
	return res + 1;
}

void merge(int pind, int lind, int rind)
{
	Node &p = P[pind];
	Node &l = P[lind];
	Node &r = P[rind];
	int cnt = reassign(lind, rind);
	DS ds(cnt);
	for (int i = 0; i < n; i++)
		if (v[l.r - 1][i] == v[r.l][i])
			ds.join(l.rcom[i], r.lcom[i]);
	p.lc = lind, p.rc = rind;
	p.com = l.com + r.com;
	p.l = l.l, p.r = r.r;
	for (int i = 0; i < n; i++)
		p.lcom[i] = l.lcom[i], p.rcom[i] = r.rcom[i];
	int *arr[] = { p.lcom, p.rcom };
	for (int j = 0; j < 2; j++)
		for (int i = 0; i < n; i++)
		{
			int &x = arr[j][i];
			if (x < cnt)
				x = ds.find(x);
		}
	for (int i = 0; i < cnt; i++)
		if (ds.find(i) != i)
			p.com--;
}

int query(int pind, int lb, int rb)
{
	Node &p = P[pind];
	if (p.l == lb && p.r == rb)
		return pind;
	Node &l = P[p.lc];
	Node &r = P[p.rc];
	if (l.r >= rb)
		return query(p.lc, lb, rb);
	if (r.l <= lb)
		return query(p.rc, lb, rb);
	int res = use++;
	int lt = query(p.lc, lb, l.r);
	use++;
	int rt = query(p.rc, r.l, rb);
	merge(res, lt, rt);
	use -= 2;
	return res;
}

int build(int l, int r, vector<vector<int>> &v)
{
	int resind = use++;
	Node &res = P[resind];
	res.l = l;
	res.r = r;
	if (r - l == 1)
	{
		for (int i = 0; i < n; i++)
		{
			res.lcom[i] = res.rcom[i] = res.com;
			if (i + 1 < n && v[l][i] != v[l][i + 1])
				res.com++;
		}
		return resind;
	}
	int m = (l + r) / 2;
	res.lc = build(l, m, v);
	res.rc = build(m, r, v);
	merge(resind, res.lc, res.rc);
	return resind;
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	v.assign(m, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf("%d", &v[j][i]);
	build(0, m, v);
	for (int l, r; q > 0; q--)
	{
		scanf("%d%d", &l, &r);
		l--;
		printf("%d\n", P[query(0, l, r)].com);
	}
}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

int n, m, q;

struct DS
{
	int n;
	vector<int> a;
	DS(int _n)
	{
		n = _n;
		a.resize(n);
		for (int i = 0; i < n; i++)
			a[i] = i;
	}
	int find(int x)
	{
		return a[x] == x ? x : a[x] = find(a[x]);
	}
	void join(int x, int y)
	{
		x = find(x);
		y = find(y);
		a[x] = y;
	}
};

struct Node
{
	Node *lc, *rc;
	int com, l, r;
	vector<int> lv, rv, lcom, rcom;
	Node()
	{
		lc = rc = NULL;
		com = 1;
		l = r = 0;
	}
} *root;

int reassign(Node *l, Node *r)
{
	int res = 0;
	map<pair<int, int>, int> M;
	for (int &x : l->rcom)
	{
		pair<int, int> pa = { 0, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : r->lcom)
	{
		pair<int, int> pa = { 1, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : l->lcom)
	{
		pair<int, int> pa = { 0, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
	}
	for (int &x : r->rcom)
	{
		pair<int, int> pa = { 1, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
	}
	return res + 1;
}

void merge(Node *p, Node *l, Node *r)
{
	int cnt = reassign(l, r);
	DS ds(cnt);
	for (int i = 0; i < n; i++)
		if (l->rv[i] == r->lv[i])
			ds.join(l->rcom[i], r->lcom[i]);
	p->lc = l, p->rc = r;
	p->com = l->com + r->com;
	p->l = l->l, p->r = r->r;
	p->lv = l->lv, p->rv = r->rv;
	p->lcom = l->lcom, p->rcom = r->rcom;
	for (int &x : p->lcom)
		if (x < cnt)
			x = ds.find(x);
	for (int &x : p->rcom)
		if (x < cnt)
			x = ds.find(x);
	for (int i = 0; i < cnt; i++)
		if (ds.find(i) != i)
			p->com--;
}

Node query(Node *p, int l, int r)
{
	if (p->l == l && p->r == r)
		return *p;
	if (p->lc->r >= r)
		return query(p->lc, l, r);
	if (p->rc->l <= l)
		return query(p->rc, l, r);
	Node res, lt = query(p->lc, l, p->lc->r), rt = query(p->rc, p->rc->l, r);
	merge(&res, &lt, &rt);
	return res;
}

Node* build(int l, int r, vector<vector<int>> &v)
{
	Node *res = new Node;
	res->l = l;
	res->r = r;
	if (r - l == 1)
	{
		res->lv = res->rv = res->lcom = res->rcom = v[l];
		for (int i = 0; i < n; i++)
		{
			res->lcom[i] = res->rcom[i] = res->com;
			if (i + 1 < n && v[l][i] != v[l][i + 1])
				res->com++;
		}
		return res;
	}
	int m = (l + r) / 2;
	res->lc = build(l, m, v);
	res->rc = build(m, r, v);
	merge(res, res->lc, res->rc);
	return res;
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	vector<vector<int>> v(m, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf("%d", &v[j][i]);
	root = build(0, m, v);
	for (int l, r; q > 0; q--)
	{
		scanf("%d%d", &l, &r);
		l--;
		printf("%d\n", query(root, l, r).com);
	}
}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

int n, m, q;
vector<vector<int>> v;

struct DS
{
	int n;
	vector<int> a;
	DS(int _n)
	{
		n = _n;
		a.resize(n);
		for (int i = 0; i < n; i++)
			a[i] = i;
	}
	int find(int x)
	{
		return a[x] == x ? x : a[x] = find(a[x]);
	}
	void join(int x, int y)
	{
		x = find(x);
		y = find(y);
		a[x] = y;
	}
};

struct Node
{
	Node *lc, *rc;
	int com, l, r;
	vector<int> lcom, rcom;
	Node()
	{
		lc = rc = NULL;
		com = 1;
		l = r = 0;
		lcom.resize(n);
		rcom.resize(n);
	}
} *root;

int reassign(Node *l, Node *r)
{
	int res = 0;
	map<pair<int, int>, int> M;
	for (int &x : l->rcom)
	{
		pair<int, int> pa = { 0, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : r->lcom)
	{
		pair<int, int> pa = { 1, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : l->lcom)
	{
		pair<int, int> pa = { 0, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
	}
	for (int &x : r->rcom)
	{
		pair<int, int> pa = { 1, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
	}
	return res + 1;
}

void merge(Node *p, Node *l, Node *r)
{
	int cnt = reassign(l, r);
	DS ds(cnt);
	for (int i = 0; i < n; i++)
		if (v[l->r-1][i] == v[r->l][i])
			ds.join(l->rcom[i], r->lcom[i]);
	p->lc = l, p->rc = r;
	p->com = l->com + r->com;
	p->l = l->l, p->r = r->r;
	p->lcom = l->lcom, p->rcom = r->rcom;
	for (int &x : p->lcom)
		if (x < cnt)
			x = ds.find(x);
	for (int &x : p->rcom)
		if (x < cnt)
			x = ds.find(x);
	for (int i = 0; i < cnt; i++)
		if (ds.find(i) != i)
			p->com--;
}

Node query(Node *p, int l, int r)
{
	if (p->l == l && p->r == r)
		return *p;
	if (p->lc->r >= r)
		return query(p->lc, l, r);
	if (p->rc->l <= l)
		return query(p->rc, l, r);
	Node res, lt = query(p->lc, l, p->lc->r), rt = query(p->rc, p->rc->l, r);
	merge(&res, &lt, &rt);
	return res;
}

Node* build(int l, int r, vector<vector<int>> &v)
{
	Node *res = new Node;
	res->l = l;
	res->r = r;
	if (r - l == 1)
	{
		for (int i = 0; i < n; i++)
		{
			res->lcom[i] = res->rcom[i] = res->com;
			if (i + 1 < n && v[l][i] != v[l][i + 1])
				res->com++;
		}
		return res;
	}
	int m = (l + r) / 2;
	res->lc = build(l, m, v);
	res->rc = build(m, r, v);
	merge(res, res->lc, res->rc);
	return res;
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	v.assign(m, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf("%d", &v[j][i]);
	root = build(0, m, v);
	for (int l, r; q > 0; q--)
	{
		scanf("%d%d", &l, &r);
		l--;
		printf("%d\n", query(root, l, r).com);
	}
}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

int n, m, q;
vector<vector<int>> v;

struct DS
{
	int n;
	vector<int> a;
	DS(int _n)
	{
		n = _n;
		a.resize(n);
		for (int i = 0; i < n; i++)
			a[i] = i;
	}
	int find(int x)
	{
		return a[x] == x ? x : a[x] = find(a[x]);
	}
	void join(int x, int y)
	{
		x = find(x);
		y = find(y);
		a[x] = y;
	}
};

struct Node
{
	Node *lc, *rc;
	int com, l, r;
	vector<int> lcom, rcom;
	Node()
	{
		lc = rc = NULL;
		com = 1;
		l = r = 0;
	}
} *root;

int reassign(Node *l, Node *r)
{
	int res = 0;
	map<pair<int, int>, int> M;
	for (int &x : l->rcom)
	{
		pair<int, int> pa = { 0, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : r->lcom)
	{
		pair<int, int> pa = { 1, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
		res = max(res, x);
	}
	for (int &x : l->lcom)
	{
		pair<int, int> pa = { 0, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
	}
	for (int &x : r->rcom)
	{
		pair<int, int> pa = { 1, x };
		if (M.find(pa) == M.end())
		{
			M[pa] = 0;
			M[pa] = M.size() - 1;
		}
		x = M[pa];
	}
	return res + 1;
}

void merge(Node *p, Node *l, Node *r)
{
	int cnt = reassign(l, r);
	DS ds(cnt);
	for (int i = 0; i < n; i++)
		if (v[l->r-1][i] == v[r->l][i])
			ds.join(l->rcom[i], r->lcom[i]);
	p->lc = l, p->rc = r;
	p->com = l->com + r->com;
	p->l = l->l, p->r = r->r;
	p->lcom = l->lcom, p->rcom = r->rcom;
	for (int &x : p->lcom)
		if (x < cnt)
			x = ds.find(x);
	for (int &x : p->rcom)
		if (x < cnt)
			x = ds.find(x);
	for (int i = 0; i < cnt; i++)
		if (ds.find(i) != i)
			p->com--;
}

Node query(Node *p, int l, int r)
{
	if (p->l == l && p->r == r)
		return *p;
	if (p->lc->r >= r)
		return query(p->lc, l, r);
	if (p->rc->l <= l)
		return query(p->rc, l, r);
	Node res, lt = query(p->lc, l, p->lc->r), rt = query(p->rc, p->rc->l, r);
	merge(&res, &lt, &rt);
	return res;
}

Node* build(int l, int r, vector<vector<int>> &v)
{
	Node *res = new Node;
	res->l = l;
	res->r = r;
	if (r - l == 1)
	{
		res->lcom.resize(n);
		res->rcom.resize(n);
		for (int i = 0; i < n; i++)
		{
			res->lcom[i] = res->rcom[i] = res->com;
			if (i + 1 < n && v[l][i] != v[l][i + 1])
				res->com++;
		}
		return res;
	}
	int m = (l + r) / 2;
	res->lc = build(l, m, v);
	res->rc = build(m, r, v);
	merge(res, res->lc, res->rc);
	return res;
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	v.assign(m, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf("%d", &v[j][i]);
	root = build(0, m, v);
	for (int l, r; q > 0; q--)
	{
		scanf("%d%d", &l, &r);
		l--;
		printf("%d\n", query(root, l, r).com);
	}
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif // M_PI
#define endl "\n"
#define S struct
#define X first
#define Y second
#define V vector
#ifndef __linux__
#define LLD "%I64d"
#else
#define LLD "%ll""d"
#endif
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;
const int MOD = 1000000007;
void sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); }
S Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;
S FAIL { FAIL () { cout << "CHANGE!!!" << endl;}};

class Dsu {
  public:
    vector <int> parent;
    //vector <int> rank;
    int comps_count_;

  public:
    void make_set(int vertex) {
    //    rank[vertex] = 1;
        parent[vertex] = vertex;
    }
    int find_set(int vertex) {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return parent[vertex] = find_set(parent[vertex]);
    }
    /*int find_set(int vertex) const {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return find_set(parent[vertex]);
    }*/
    void union_sets(int first, int second) {
        first = find_set(first);
        second = find_set(second);
        if (first != second) {
            --comps_count_;
            //if (rank[first] < rank[second]) {
            //   std::swap(first, second);
            //}
            parent[second] = first;
            //if (rank[first] == rank[second]) {
            //    ++rank[first];
            //}
        }
    }
    void init(int numbers_count) {
        comps_count_ = numbers_count;
        //rank.resize(numbers_count);
        parent.resize(numbers_count);
        for (int i = 0; i < numbers_count; ++i) {
           make_set(i);
        }
    }
    Dsu(int numbers_count) {
       init(numbers_count);
    }
    Dsu() {
       init(0);
    }
    int size() const {
        return parent.size();
    }
    friend Dsu merge(const Dsu &first, const Dsu &second) {
        Dsu result;
        result.parent.resize(first.size() + second.size());
        //result.rank.resize(first.size() + second.size());
        result.comps_count_ = first.comps_count() + second.comps_count();
        for (int i = 0; i < first.size(); ++i) {
            result.parent[i] = first.parent[i];
        //    result.rank[i] = first.rank[i];
        }
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] = second.parent[i] + first.size();
        //    result.rank[i + first.size()] = second.rank[i];
        }
        return result;
    }
    friend Dsu left_right(const Dsu &dsu, int n);
    int comps_count() const {
        return comps_count_;
    }
};

Dsu calculate(const vector <vector <int>> &data, int left, int right)
{
    int n = data.size();
    assert(left == right);
    Dsu result((right - left + 1) * n);
    result.parent[0] = 0;
    result.comps_count_ = 1;
    FOR (i, 1, n) {
        if (data[i][left] == data[i - 1][left]) {
            result.parent[i] = result.parent[i - 1];
        } else {
            result.parent[i] = i;
            ++result.comps_count_;
        }
    }
    return result;
}

int redir[1000003];

Dsu left_right(Dsu &dsu, int n)
{
    Dsu result;
    if (dsu.size() == 0) {
        return dsu;
    }
    FOR (i, 0, dsu.size()) {
        dsu.find_set(i);
    }
    result.parent.reserve(2 * n);
    if (dsu.size() == n) {
        result.parent.resize(2 * n);
        FOR (i, 0, n) {
            result.parent[i] = dsu.parent[i];
        }
        FOR (i, n, 2 * n) {
            result.parent[i] = dsu.parent[i - n];
        }
        result.comps_count_ = dsu.comps_count_;
        return result;
    }
    //result.rank.reserve(2 * n);
    FOR (i, 0, n) {
        result.parent.push_back(dsu.parent[i]);
    //    result.rank.push_back(dsu.rank[i]);
    }
    FOR (i, dsu.size() - n, dsu.size()) {
        result.parent.push_back(dsu.parent[i]);
    //    result.rank.push_back(dsu.rank[i]);
    }
    vector <int> used;
    FOR (i, 0, result.parent.size()) {
        if (redir[result.parent[i]] != -1) {
            result.parent[i] = redir[result.parent[i]];
        } else {
            redir[result.parent[i]] = i;
            used.push_back(result.parent[i]);
            result.parent[i] = i;
        }
    }
    for (auto elem: used) {
        redir[elem] = -1;
    }
    result.comps_count_ = dsu.comps_count_;
    return result;
}

#include <sys/time.h>

long long myclock()
{
    timeval start;
    gettimeofday(&start, NULL);
    return (long long)start.tv_sec * 1000000 + start.tv_usec;
}

LL t1 = 0;
LL t2 = 0;
LL t3 = 0;
LL t4 = 0;
LL build_cnt = 0;

class SegmentTree
{
  public:
    SegmentTree(vector <vector <int>> &data_)
      : data(data_) {
        int n = data[0].size();
        t.resize(4 * n);
        build(data, 0, 0, n - 1);
    }

    Dsu query(int left, int right) {
        return query(0, 0, data[0].size() - 1, left, right);
    }

  private:
    void build(vector <vector <int>> &data, int vertex, int left, int right) {
        if (left == right) {
            t[vertex] = calculate(data, left, right);
            LL prev = myclock();
            t[vertex] = left_right(t[vertex], data.size());
            t1 += myclock() - prev;
        } else {
            int mid = (left + right) / 2;
            build(data, 2 * vertex + 1, left, mid);
            build(data, 2 * vertex + 2, mid + 1, right);
            t[vertex] = tree_merge(t[2 * vertex + 1], t[2 * vertex + 2], mid);
        }
    }

    Dsu tree_merge(const Dsu &first, const Dsu &second, int shift) {
        if (first.size() == 0) {
            return second;
        }
        if (second.size() == 0) {
            return first;
        }
        Dsu result = merge(first, second);
        int y = shift;
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            if (data[i][y] == data[i][y + 1]) {
                result.union_sets(n + i, 2 * n + i);
            }
        }
        result = left_right(result, data.size());
        return result;
    }

    Dsu query(int vertex, int tl, int tr, int left, int right) {
        if (left > right) {
            return Dsu();
        }
        if (tl == left && tr == right) {
            return t[vertex];
        }
        int tm = (tl + tr) / 2;
        return tree_merge(query(2 * vertex + 1, tl, tm, left, min(right, tm)),
                          query(2 * vertex + 2, tm + 1, tr, max(left, tm + 1), right), tm);
    }
    vector <Dsu> t;
    vector <vector <int>> data;
};

int main()
{
    FOR (i, 0, 1000003) {
        redir[i] = -1;
    }
    int n, m, q;
    cin >> n >> m >> q;
    vector <vector <int>> v(n, vector <int> (m));
    GETM(v, n, m);
    SegmentTree tree(v);
    //DEB(t1);
    //return 0;
    FOR (i, 0, q) {
        int l, r;
        cin >> l >> r;
        --l, --r;
        Dsu res = tree.query(l, r);
        cout << res.comps_count() << endl;
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif // M_PI
#define endl "\n"
#define S struct
#define X first
#define Y second
#define V vector
#ifndef __linux__
#define LLD "%I64d"
#else
#define LLD "%ll""d"
#endif
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;
const int MOD = 1000000007;
void sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); }
S Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;
S FAIL { FAIL () { cout << "CHANGE!!!" << endl;}};

class Dsu {
  public:
    vector <int> parent;
    vector <int> rank;
    int comps_count_;

  public:
    void make_set(int vertex) {
        rank[vertex] = 1;
        parent[vertex] = vertex;
    }
    int find_set(int vertex) {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return parent[vertex] = find_set(parent[vertex]);
    }
    /*int find_set(int vertex) const {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return find_set(parent[vertex]);
    }*/
    void union_sets(int first, int second) {
        first = find_set(first);
        second = find_set(second);
        if (first != second) {
            --comps_count_;
            if (rank[first] < rank[second]) {
               std::swap(first, second);
            }
            parent[second] = first;
            if (rank[first] == rank[second]) {
                ++rank[first];
            }
        }
    }
    void init(int numbers_count) {
        comps_count_ = numbers_count;
        rank.resize(numbers_count);
        parent.resize(numbers_count);
        for (int i = 0; i < numbers_count; ++i) {
           make_set(i);
        }
    }
    Dsu(int numbers_count) {
       init(numbers_count);
    }
    Dsu() {
       init(0);
    }
    int size() const {
        return parent.size();
    }
    friend Dsu merge(const Dsu &first, const Dsu &second) {
        Dsu result;
        result.parent.resize(first.size() + second.size());
        result.rank.resize(first.size() + second.size());
        result.comps_count_ = first.comps_count() + second.comps_count();
        for (int i = 0; i < first.size(); ++i) {
            result.parent[i] = first.parent[i];
            result.rank[i] = first.rank[i];
        }
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] = second.parent[i] + first.size();
            result.rank[i + first.size()] = second.rank[i];
        }
        return result;
    }
    friend Dsu left_right(const Dsu &dsu, int n);
    int comps_count() const {
        return comps_count_;
    }
};

Dsu calculate(const vector <vector <int>> &data, int left, int right)
{
    int n = data.size();
    Dsu result((right - left + 1) * n);
    FOR (i, 0, n) {
        FOR (j, 0, right - left) {
            if (data[i][left + j] == data[i][left + j + 1]) {
                result.union_sets(j * n + i, (j + 1) * n + i);
            }
        }
    }
    FOR (i, 0, n - 1) {
        FOR (j, 0, right - left + 1) {
            if (data[i][left + j] == data[i + 1][left + j]) {
                result.union_sets(j * n + i, j * n + i + 1);
            }
        }
    }
    return result;
}

int redir[1000003];

Dsu left_right(Dsu &dsu, int n)
{
    Dsu result;
    if (dsu.size() == 0) {
        return dsu;
    }
    FOR (i, 0, dsu.size()) {
        dsu.find_set(i);
    }
    FOR (i, 0, n) {
        result.parent.push_back(dsu.parent[i]);
        result.rank.push_back(dsu.rank[i]);
    }
    FOR (i, dsu.size() - n, dsu.size()) {
        result.parent.push_back(dsu.parent[i]);
        result.rank.push_back(dsu.rank[i]);
    }
    vector <int> used;
    FOR (i, 0, result.parent.size()) {
        if (redir[result.parent[i]] != -1) {
            result.parent[i] = redir[result.parent[i]];
        } else {
            redir[result.parent[i]] = i;
            used.push_back(result.parent[i]);
            result.parent[i] = i;
        }
    }
    for (auto elem: used) {
        redir[elem] = -1;
    }
    result.comps_count_ = dsu.comps_count_;
    return result;
}

class SegmentTree
{
  public:
    SegmentTree(vector <vector <int>> &data_)
      : data(data_) {
        int n = data[0].size();
        t.resize(4 * n);
        build(data, 0, 0, n - 1);
    }

    Dsu query(int left, int right) {
        return query(0, 0, data[0].size() - 1, left, right);
    }

  private:
    void build(vector <vector <int>> &data, int vertex, int left, int right) {
        if (left == right) {
            t[vertex] = calculate(data, left, right);
            t[vertex] = left_right(t[vertex], data.size());
        } else {
            int mid = (left + right) / 2;
            build(data, 2 * vertex + 1, left, mid);
            build(data, 2 * vertex + 2, mid + 1, right);
            t[vertex] = tree_merge(t[2 * vertex + 1], t[2 * vertex + 2], mid);
        }
    }

    Dsu tree_merge(const Dsu &first, const Dsu &second, int shift) {
        if (first.size() == 0) {
            return second;
        }
        if (second.size() == 0) {
            return first;
        }
        Dsu result = merge(first, second);
        int y = shift;
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            if (data[i][y] == data[i][y + 1]) {
                result.union_sets(n + i, 2 * n + i);
            }
        }
        result = left_right(result, data.size());
        return result;
    }

    Dsu query(int vertex, int tl, int tr, int left, int right) {
        if (left > right) {
            return Dsu();
        }
        if (tl == left && tr == right) {
            return t[vertex];
        }
        int tm = (tl + tr) / 2;
        return tree_merge(query(2 * vertex + 1, tl, tm, left, min(right, tm)),
                          query(2 * vertex + 2, tm + 1, tr, max(left, tm + 1), right), tm);
    }
    vector <Dsu> t;
    vector <vector <int>> data;
};

int main()
{
    FOR (i, 0, 1000003) {
        redir[i] = -1;
    }
    int n, m, q;
    cin >> n >> m >> q;
    vector <vector <int>> v(n, vector <int> (m));
    GETM(v, n, m);
    SegmentTree tree(v);
    //return 0;
    FOR (i, 0, q) {
        int l, r;
        cin >> l >> r;
        --l, --r;
        Dsu res = tree.query(l, r);
        cout << res.comps_count() << endl;
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif // M_PI
#define endl "\n"
#define S struct
#define X first
#define Y second
#define V vector
#ifndef __linux__
#define LLD "%I64d"
#else
#define LLD "%ll""d"
#endif
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;
const int MOD = 1000000007;
void sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); }
S Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;
S FAIL { FAIL () { cout << "CHANGE!!!" << endl;}};

class Dsu {
  public:
    vector <int> parent;
    vector <int> rank;
    int comps_count_;

  public:
    void make_set(int vertex) {
        rank[vertex] = 1;
        parent[vertex] = vertex;
    }
    int find_set(int vertex) {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return parent[vertex] = find_set(parent[vertex]);
    }
    int find_set(int vertex) const {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return find_set(parent[vertex]);
    }
    void union_sets(int first, int second) {
        first = find_set(first);
        second = find_set(second);
        if (first != second) {
            --comps_count_;
            if (rank[first] < rank[second]) {
               std::swap(first, second);
            }
            parent[second] = first;
            if (rank[first] == rank[second]) {
                ++rank[first];
            }
        }
    }
    void init(int numbers_count) {
        comps_count_ = numbers_count;
        rank.resize(numbers_count);
        parent.resize(numbers_count);
        for (int i = 0; i < numbers_count; ++i) {
           make_set(i);
        }
    }
    Dsu(int numbers_count) {
       init(numbers_count);
    }
    Dsu() {
       init(0);
    }
    int size() const {
        return parent.size();
    }
    friend Dsu merge(const Dsu &first, const Dsu &second) {
        Dsu result;
        result.parent.resize(first.size() + second.size());
        result.rank.resize(first.size() + second.size());
        result.comps_count_ = first.comps_count() + second.comps_count();
        for (int i = 0; i < first.size(); ++i) {
            result.parent[i] = first.parent[i];
            result.rank[i] = first.rank[i];
        }
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] = second.parent[i] + first.size();
            result.rank[i + first.size()] = second.rank[i];
        }
        return result;
    }
    friend Dsu left_right(const Dsu &dsu, int n);
    int comps_count() const {
        return comps_count_;
    }
};

Dsu calculate(const vector <vector <int>> &data, int left, int right)
{
    int n = data.size();
    Dsu result((right - left + 1) * n);
    FOR (i, 0, n) {
        FOR (j, 0, right - left) {
            if (data[i][left + j] == data[i][left + j + 1]) {
                result.union_sets(j * n + i, (j + 1) * n + i);
            }
        }
    }
    FOR (i, 0, n - 1) {
        FOR (j, 0, right - left + 1) {
            if (data[i][left + j] == data[i + 1][left + j]) {
                result.union_sets(j * n + i, j * n + i + 1);
            }
        }
    }
    return result;
}

Dsu left_right(const Dsu &dsu, int n)
{
    Dsu result;
    if (dsu.size() == 0) {
        return dsu;
    }
    FOR (i, 0, n) {
        result.parent.push_back(dsu.parent[i]);
        result.rank.push_back(dsu.rank[i]);
    }
    FOR (i, dsu.size() - n, dsu.size()) {
        result.parent.push_back(dsu.parent[i]);
        result.rank.push_back(dsu.rank[i]);
    }
    map <int, int> redir;
    FOR (i, 0, result.parent.size()) {
        if (redir.find(result.parent[i]) != redir.end()) {
            result.parent[i] = redir[result.parent[i]];
        } else {
            redir[result.parent[i]] = i;
            result.parent[i] = i;
        }
    }
    result.comps_count_ = dsu.comps_count_;
    return result;
}

class SegmentTree
{
  public:
    SegmentTree(vector <vector <int>> &data_)
      : data(data_) {
        int n = data[0].size();
        t.resize(4 * n);
        build(data, 0, 0, n - 1);
    }

    Dsu query(int left, int right) {
        return query(0, 0, data[0].size() - 1, left, right);
    }

  private:
    void build(vector <vector <int>> &data, int vertex, int left, int right) {
        t[vertex] = calculate(data, left, right);
        t[vertex] = left_right(t[vertex], data.size());
        if (left == right) {
            return;
        }
        int mid = (left + right) / 2;
        build(data, 2 * vertex + 1, left, mid);
        build(data, 2 * vertex + 2, mid + 1, right);
    }

    Dsu tree_merge(const Dsu &first, const Dsu &second, int shift) {
        if (first.size() == 0) {
            return second;
        }
        if (second.size() == 0) {
            return first;
        }
//        DEB(first.comps_count());
//        DEBA(first.parent);
//        DEB(second.comps_count());
//        DEBA(second.parent);
//        DEB(shift);
        Dsu result = merge(first, second);
        int y = shift;
//        DEB(y);
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            if (data[i][y] == data[i][y + 1]) {
                result.union_sets(n + i, 2 * n + i);
            }
        }
        result = left_right(result, data.size());
        return result;
    }

    Dsu query(int vertex, int tl, int tr, int left, int right) {
        if (left > right) {
            return Dsu();
        }
        if (tl == left && tr == right) {
            return t[vertex];
        }
        int tm = (tl + tr) / 2;
        return tree_merge(query(2 * vertex + 1, tl, tm, left, min(right, tm)),
                          query(2 * vertex + 2, tm + 1, tr, max(left, tm + 1), right), tm);
    }
    vector <Dsu> t;
    vector <vector <int>> data;
};

int main()
{
    int n, m, q;
    cin >> n >> m >> q;
    vector <vector <int>> v(n, vector <int> (m));
    GETM(v, n, m);
    SegmentTree tree(v);
    FOR (i, 0, q) {
        int l, r;
        cin >> l >> r;
        --l, --r;
        Dsu res = tree.query(l, r);
        cout << res.comps_count() << endl;
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif // M_PI
#define endl "\n"
#define S struct
#define X first
#define Y second
#define V vector
#ifndef __linux__
#define LLD "%I64d"
#else
#define LLD "%ll""d"
#endif
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;
const int MOD = 1000000007;
void sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); }
S Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;
S FAIL { FAIL () { cout << "CHANGE!!!" << endl;}};

class Dsu {
  public:
    vector <int> parent;
    vector <int> rank;
    int comps_count_;

  public:
    void make_set(int vertex) {
        rank[vertex] = 1;
        parent[vertex] = vertex;
    }
    int find_set(int vertex) {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return parent[vertex] = find_set(parent[vertex]);
    }
    /*int find_set(int vertex) const {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return find_set(parent[vertex]);
    }*/
    void union_sets(int first, int second) {
        first = find_set(first);
        second = find_set(second);
        if (first != second) {
            --comps_count_;
            if (rank[first] < rank[second]) {
               std::swap(first, second);
            }
            parent[second] = first;
            if (rank[first] == rank[second]) {
                ++rank[first];
            }
        }
    }
    void init(int numbers_count) {
        comps_count_ = numbers_count;
        rank.resize(numbers_count);
        parent.resize(numbers_count);
        for (int i = 0; i < numbers_count; ++i) {
           make_set(i);
        }
    }
    Dsu(int numbers_count) {
       init(numbers_count);
    }
    Dsu() {
       init(0);
    }
    int size() const {
        return parent.size();
    }
    friend Dsu merge(const Dsu &first, const Dsu &second) {
        Dsu result;
        result.parent.resize(first.size() + second.size());
        result.rank.resize(first.size() + second.size());
        result.comps_count_ = first.comps_count() + second.comps_count();
        for (int i = 0; i < first.size(); ++i) {
            result.parent[i] = first.parent[i];
            result.rank[i] = first.rank[i];
        }
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] = second.parent[i] + first.size();
            result.rank[i + first.size()] = second.rank[i];
        }
        return result;
    }
    friend Dsu left_right(const Dsu &dsu, int n);
    int comps_count() const {
        return comps_count_;
    }
};

Dsu calculate(const vector <vector <int>> &data, int left, int right)
{
    int n = data.size();
    assert(left == right);
    Dsu result((right - left + 1) * n);
    FOR (i, 0, n) {
        FOR (j, 0, right - left) {
            if (data[i][left + j] == data[i][left + j + 1]) {
                result.union_sets(j * n + i, (j + 1) * n + i);
            }
        }
    }
    FOR (i, 0, n - 1) {
        FOR (j, 0, right - left + 1) {
            if (data[i][left + j] == data[i + 1][left + j]) {
                result.union_sets(j * n + i, j * n + i + 1);
            }
        }
    }
    return result;
}

int redir[1000003];

Dsu left_right(Dsu &dsu, int n)
{
    Dsu result;
    if (dsu.size() == 0) {
        return dsu;
    }
    FOR (i, 0, dsu.size()) {
        dsu.find_set(i);
    }
    result.parent.reserve(2 * n);
    result.rank.reserve(2 * n);
    FOR (i, 0, n) {
        result.parent.push_back(dsu.parent[i]);
        result.rank.push_back(dsu.rank[i]);
    }
    FOR (i, dsu.size() - n, dsu.size()) {
        result.parent.push_back(dsu.parent[i]);
        result.rank.push_back(dsu.rank[i]);
    }
    if (dsu.size() == n) {
        FOR (i, 0, n) {
            result.parent[i] = dsu.parent[i];
        }
        FOR (i, n, 2 * n) {
            result.parent[i] = dsu.parent[i - n];
        }
    }
    vector <int> used;
    FOR (i, 0, result.parent.size()) {
        if (redir[result.parent[i]] != -1) {
            result.parent[i] = redir[result.parent[i]];
        } else {
            redir[result.parent[i]] = i;
            used.push_back(result.parent[i]);
            result.parent[i] = i;
        }
    }
    for (auto elem: used) {
        redir[elem] = -1;
    }
    result.comps_count_ = dsu.comps_count_;
    return result;
}

#include <sys/time.h>

long long myclock()
{
    timeval start;
    gettimeofday(&start, NULL);
    return (long long)start.tv_sec * 1000000 + start.tv_usec;
}

LL t1 = 0;
LL t2 = 0;
LL t3 = 0;
LL t4 = 0;
LL build_cnt = 0;

class SegmentTree
{
  public:
    SegmentTree(vector <vector <int>> &data_)
      : data(data_) {
        int n = data[0].size();
        t.resize(4 * n);
        build(data, 0, 0, n - 1);
    }

    Dsu query(int left, int right) {
        return query(0, 0, data[0].size() - 1, left, right);
    }

  private:
    void build(vector <vector <int>> &data, int vertex, int left, int right) {
        if (left == right) {
            t[vertex] = calculate(data, left, right);
            LL prev = myclock();
            t[vertex] = left_right(t[vertex], data.size());
            t1 += myclock() - prev;
        } else {
            int mid = (left + right) / 2;
            build(data, 2 * vertex + 1, left, mid);
            build(data, 2 * vertex + 2, mid + 1, right);
            t[vertex] = tree_merge(t[2 * vertex + 1], t[2 * vertex + 2], mid);
        }
    }

    Dsu tree_merge(const Dsu &first, const Dsu &second, int shift) {
        if (first.size() == 0) {
            return second;
        }
        if (second.size() == 0) {
            return first;
        }
        Dsu result = merge(first, second);
        int y = shift;
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            if (data[i][y] == data[i][y + 1]) {
                result.union_sets(n + i, 2 * n + i);
            }
        }
        result = left_right(result, data.size());
        return result;
    }

    Dsu query(int vertex, int tl, int tr, int left, int right) {
        if (left > right) {
            return Dsu();
        }
        if (tl == left && tr == right) {
            return t[vertex];
        }
        int tm = (tl + tr) / 2;
        return tree_merge(query(2 * vertex + 1, tl, tm, left, min(right, tm)),
                          query(2 * vertex + 2, tm + 1, tr, max(left, tm + 1), right), tm);
    }
    vector <Dsu> t;
    vector <vector <int>> data;
};

int main()
{
    FOR (i, 0, 1000003) {
        redir[i] = -1;
    }
    int n, m, q;
    cin >> n >> m >> q;
    vector <vector <int>> v(n, vector <int> (m));
    GETM(v, n, m);
    SegmentTree tree(v);
    //DEB(t1);
    //return 0;
    FOR (i, 0, q) {
        int l, r;
        cin >> l >> r;
        --l, --r;
        Dsu res = tree.query(l, r);
        cout << res.comps_count() << endl;
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif // M_PI
#define endl "\n"
#define S struct
#define X first
#define Y second
#define V vector
#ifndef __linux__
#define LLD "%I64d"
#else
#define LLD "%ll""d"
#endif
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;
const int MOD = 1000000007;
void sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); }
S Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;
S FAIL { FAIL () { cout << "CHANGE!!!" << endl;}};

class Dsu {
  public:
    vector <int> parent;
    //vector <int> rank;
    int comps_count_;

  public:
    void make_set(int vertex) {
    //    rank[vertex] = 1;
        parent[vertex] = vertex;
    }
    int find_set(int vertex) {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return parent[vertex] = find_set(parent[vertex]);
    }
    /*int find_set(int vertex) const {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return find_set(parent[vertex]);
    }*/
    void union_sets(int first, int second) {
        first = find_set(first);
        second = find_set(second);
        if (first != second) {
            --comps_count_;
            /*if (rank[first] < rank[second]) {
               std::swap(first, second);
            }*/
            parent[second] = first;
            /*if (rank[first] == rank[second]) {
                ++rank[first];
            }*/
        }
    }
    void init(int numbers_count) {
        comps_count_ = numbers_count;
        //rank.resize(numbers_count);
        parent.resize(numbers_count);
        for (int i = 0; i < numbers_count; ++i) {
           make_set(i);
        }
    }
    Dsu(int numbers_count) {
       init(numbers_count);
    }
    Dsu() {
       init(0);
    }
    int size() const {
        return parent.size();
    }
    friend Dsu merge(const Dsu &first, const Dsu &second) {
        Dsu result;
        result.parent.resize(first.size() + second.size());
        //result.rank.resize(first.size() + second.size());
        result.comps_count_ = first.comps_count() + second.comps_count();
        for (int i = 0; i < first.size(); ++i) {
            result.parent[i] = first.parent[i];
        //    result.rank[i] = first.rank[i];
        }
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] = second.parent[i] + first.size();
        //    result.rank[i + first.size()] = second.rank[i];
        }
        return result;
    }
    friend Dsu left_right(const Dsu &dsu, int n);
    int comps_count() const {
        return comps_count_;
    }
};

Dsu calculate(const vector <vector <int>> &data, int left, int right)
{
    int n = data.size();
    assert(left == right);
    Dsu result((right - left + 1) * n);
    result.parent[0] = 0;
    /*FOR (i, 1, n) {
        if (data[i][left] == data[i - 1][left]) {
            result.parent[i] = result.parent[i - 1];
        } else {
            result.parent[i] = i;
        }
    }*/
    FOR (i, 0, n) {
        FOR (j, 0, right - left) {
            if (data[i][left + j] == data[i][left + j + 1]) {
                result.union_sets(j * n + i, (j + 1) * n + i);
            }
        }
    }
    FOR (i, 0, n - 1) {
        FOR (j, 0, right - left + 1) {
            if (data[i][left + j] == data[i + 1][left + j]) {
                result.union_sets(j * n + i, j * n + i + 1);
            }
        }
    }
    return result;
}

int redir[1000003];

Dsu left_right(Dsu &dsu, int n)
{
    Dsu result;
    if (dsu.size() == 0) {
        return dsu;
    }
    FOR (i, 0, dsu.size()) {
        dsu.find_set(i);
    }
    result.parent.reserve(2 * n);
    //result.rank.reserve(2 * n);
    FOR (i, 0, n) {
        result.parent.push_back(dsu.parent[i]);
    //    result.rank.push_back(dsu.rank[i]);
    }
    FOR (i, dsu.size() - n, dsu.size()) {
        result.parent.push_back(dsu.parent[i]);
    //    result.rank.push_back(dsu.rank[i]);
    }
    if (dsu.size() == n) {
        FOR (i, 0, n) {
            result.parent[i] = dsu.parent[i];
        }
        FOR (i, n, 2 * n) {
            result.parent[i] = dsu.parent[i - n];
        }
        result.comps_count_ = dsu.comps_count_;
        //return result;
    }
    vector <int> used;
    FOR (i, 0, result.parent.size()) {
        if (redir[result.parent[i]] != -1) {
            result.parent[i] = redir[result.parent[i]];
        } else {
            redir[result.parent[i]] = i;
            used.push_back(result.parent[i]);
            result.parent[i] = i;
        }
    }
    for (auto elem: used) {
        redir[elem] = -1;
    }
    result.comps_count_ = dsu.comps_count_;
    return result;
}

#include <sys/time.h>

long long myclock()
{
    timeval start;
    gettimeofday(&start, NULL);
    return (long long)start.tv_sec * 1000000 + start.tv_usec;
}

LL t1 = 0;
LL t2 = 0;
LL t3 = 0;
LL t4 = 0;
LL build_cnt = 0;

class SegmentTree
{
  public:
    SegmentTree(vector <vector <int>> &data_)
      : data(data_) {
        int n = data[0].size();
        t.resize(4 * n);
        build(data, 0, 0, n - 1);
    }

    Dsu query(int left, int right) {
        return query(0, 0, data[0].size() - 1, left, right);
    }

  private:
    void build(vector <vector <int>> &data, int vertex, int left, int right) {
        if (left == right) {
            t[vertex] = calculate(data, left, right);
            LL prev = myclock();
            t[vertex] = left_right(t[vertex], data.size());
            t1 += myclock() - prev;
        } else {
            int mid = (left + right) / 2;
            build(data, 2 * vertex + 1, left, mid);
            build(data, 2 * vertex + 2, mid + 1, right);
            t[vertex] = tree_merge(t[2 * vertex + 1], t[2 * vertex + 2], mid);
        }
    }

    Dsu tree_merge(const Dsu &first, const Dsu &second, int shift) {
        if (first.size() == 0) {
            return second;
        }
        if (second.size() == 0) {
            return first;
        }
        Dsu result = merge(first, second);
        int y = shift;
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            if (data[i][y] == data[i][y + 1]) {
                result.union_sets(n + i, 2 * n + i);
            }
        }
        result = left_right(result, data.size());
        return result;
    }

    Dsu query(int vertex, int tl, int tr, int left, int right) {
        if (left > right) {
            return Dsu();
        }
        if (tl == left && tr == right) {
            return t[vertex];
        }
        int tm = (tl + tr) / 2;
        return tree_merge(query(2 * vertex + 1, tl, tm, left, min(right, tm)),
                          query(2 * vertex + 2, tm + 1, tr, max(left, tm + 1), right), tm);
    }
    vector <Dsu> t;
    vector <vector <int>> data;
};

int main()
{
    FOR (i, 0, 1000003) {
        redir[i] = -1;
    }
    int n, m, q;
    cin >> n >> m >> q;
    vector <vector <int>> v(n, vector <int> (m));
    GETM(v, n, m);
    SegmentTree tree(v);
    //DEB(t1);
    //return 0;
    FOR (i, 0, q) {
        int l, r;
        cin >> l >> r;
        --l, --r;
        Dsu res = tree.query(l, r);
        cout << res.comps_count() << endl;
    }
}


#include <bits/stdc++.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif // M_PI
#define endl "\n"
#define S struct
#define X first
#define Y second
#define V vector
#ifndef __linux__
#define LLD "%I64d"
#else
#define LLD "%ll""d"
#endif
#define FOR(x, y, z) for (int x = (y); x < (z); ++x)
#define FORR(x, y, z) for (int x = (y); x > (z); --x)
#define GET(a, n) for (int __i = 0; __i < (n); ++__i) cin >> a[__i];
#define GETM(a, n, m) for (int __i = 0; __i < (n); ++__i) for (int __j = 0; __j < m; ++__j) cin >> a[__i][__j];
#define PRINTM(a, n, m) for (int __i = 0; __i < (n); ++__i) { for (int __j = 0; __j < m; ++__j) cout << a[__i][__j] << " ";  cout << endl; };
#define PRINT(a, n) for (int __i = 0; __i < (n); ++__i) cout << a[__i] << " ";
#define IT(a) a.begin(), a.end()
#define SQR(x) (x) * (x)
#define CASE(a, s) cout << "Case #" << a << ": " << s << endl;
#define DEB(a) cout << #a << " = " << (a) << endl; cout.flush();
#define DEBA(a) for (auto __i: a) cout << __i << " "; cout << endl; cout.flush();
#define IFDEB(b, a) if (b) { cout << #a << " = " << (a) << endl; cout.flush(); }
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;
const int MOD = 1000000007;
void sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); }
S Sync_stdio { Sync_stdio() { cin.tie(NULL); ios_base::sync_with_stdio(false); } } _sync_stdio;
S FAIL { FAIL () { cout << "CHANGE!!!" << endl;}};

class Dsu {
  public:
    vector <int> parent;
    //vector <int> rank;
    int comps_count_;

  public:
    void make_set(int vertex) {
    //    rank[vertex] = 1;
        parent[vertex] = vertex;
    }
    int find_set(int vertex) {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return parent[vertex] = find_set(parent[vertex]);
    }
    /*int find_set(int vertex) const {
        if (vertex == parent[vertex]) {
            return vertex;
        }
        return find_set(parent[vertex]);
    }*/
    void union_sets(int first, int second) {
        first = find_set(first);
        second = find_set(second);
        if (first != second) {
            --comps_count_;
            //if (rank[first] < rank[second]) {
            //   std::swap(first, second);
            //}
            parent[second] = first;
            //if (rank[first] == rank[second]) {
            //    ++rank[first];
            //}
        }
    }
    void init(int numbers_count) {
        comps_count_ = numbers_count;
        //rank.resize(numbers_count);
        parent.resize(numbers_count);
        for (int i = 0; i < numbers_count; ++i) {
           make_set(i);
        }
    }
    Dsu(int numbers_count) {
       init(numbers_count);
    }
    Dsu() {
       init(0);
    }
    int size() const {
        return parent.size();
    }
    friend Dsu merge(const Dsu &first, const Dsu &second) {
        Dsu result;
        result.parent.resize(first.size() + second.size());
        //result.rank.resize(first.size() + second.size());
        result.comps_count_ = first.comps_count() + second.comps_count();
        copy(first.parent.begin(), first.parent.end(), result.parent.begin());
        copy(second.parent.begin(), second.parent.end(), result.parent.begin() + first.size());
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] += first.size();
        }
        /*for (int i = 0; i < first.size(); ++i) {
            result.parent[i] = first.parent[i];
        //    result.rank[i] = first.rank[i];
        }
        for (int i = 0; i < second.size(); ++i) {
            result.parent[i + first.size()] = second.parent[i] + first.size();
        //    result.rank[i + first.size()] = second.rank[i];
        }*/
        return result;
    }
    friend Dsu left_right(const Dsu &dsu, int n);
    int comps_count() const {
        return comps_count_;
    }
};

Dsu calculate(const vector <vector <int>> &data, int left, int right)
{
    int n = data.size();
    assert(left == right);
    Dsu result((right - left + 1) * n);
    result.parent[0] = 0;
    result.comps_count_ = 1;
    FOR (i, 1, n) {
        if (data[i][left] == data[i - 1][left]) {
            result.parent[i] = result.parent[i - 1];
        } else {
            result.parent[i] = i;
            ++result.comps_count_;
        }
    }
    return result;
}

int redir[1000003];

#include <sys/time.h>

long long myclock()
{
    timeval start;
    gettimeofday(&start, NULL);
    return (long long)start.tv_sec * 1000000 + start.tv_usec;
}

LL t1 = 0;
LL t2 = 0;
LL t3 = 0;
LL t4 = 0;
LL build_cnt = 0;

Dsu left_right(Dsu &dsu, int n)
{
    FOR (i, 0, dsu.size()) {
        dsu.find_set(i);
    }
    if (dsu.size() <= n) {
        return dsu;
    }
    Dsu result;
    result.parent.resize(2 * n);
    copy(dsu.parent.begin(), dsu.parent.begin() + n, result.parent.begin());
    copy(dsu.parent.end() - n, dsu.parent.end(), result.parent.begin() + n);
    vector <int> used;
    used.reserve(2 * n);
    FOR (i, 0, result.parent.size()) {
        if (redir[result.parent[i]] != -1) {
            result.parent[i] = redir[result.parent[i]];
        } else {
            redir[result.parent[i]] = i;
            used.push_back(result.parent[i]);
            result.parent[i] = i;
        }
    }
    for (auto elem: used) {
        redir[elem] = -1;
    }
    result.comps_count_ = dsu.comps_count_;
    return result;
}

class SegmentTree
{
  public:
    SegmentTree(vector <vector <int>> &data_)
      : data(data_) {
        int n = data[0].size();
        t.resize(4 * n);
        build(data, 0, 0, n - 1);
    }

    Dsu query(int left, int right) {
        return query(0, 0, data[0].size() - 1, left, right);
    }

  private:
    void build(const vector <vector <int>> &data, int vertex, int left, int right) {
        if (left == right) {
            t[vertex] = calculate(data, left, right);
            t[vertex] = left_right(t[vertex], data.size());
        } else {
            int mid = (left + right) / 2;
            build(data, 2 * vertex + 1, left, mid);
            build(data, 2 * vertex + 2, mid + 1, right);
            t[vertex] = tree_merge(t[2 * vertex + 1], t[2 * vertex + 2], mid);
        }
    }

    Dsu tree_merge(const Dsu &first, const Dsu &second, int shift) {
        if (first.size() == 0) {
            return second;
        }
        if (second.size() == 0) {
            return first;
        }
        Dsu result = merge(first, second);
        int y = shift;
        int n = data.size();
        for (int i = 0; i < n; ++i) {
            if (data[i][y] == data[i][y + 1]) {
                result.union_sets(first.size() - n + i, first.size() + i);
            }
        }
        result = left_right(result, data.size());
        return result;
    }

    Dsu query(int vertex, int tl, int tr, int left, int right) {
        if (left > right) {
            return Dsu();
        }
        if (tl == left && tr == right) {
            return t[vertex];
        }
        int tm = (tl + tr) / 2;
        return tree_merge(query(2 * vertex + 1, tl, tm, left, min(right, tm)),
                          query(2 * vertex + 2, tm + 1, tr, max(left, tm + 1), right), tm);
    }
    vector <Dsu> t;
    const vector <vector <int>> &data;
};

int main()
{
    FOR (i, 0, 1000003) {
        redir[i] = -1;
    }
    int n, m, q;
    cin >> n >> m >> q;
    vector <vector <int>> v(n, vector <int> (m));
    GETM(v, n, m);
    SegmentTree tree(v);
    //DEB(t1);
    //return 0;
    FOR (i, 0, q) {
        int l, r;
        cin >> l >> r;
        --l, --r;
        Dsu res = tree.query(l, r);
        cout << res.comps_count() << endl;
    }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int is_fib(ll k,ll a[],ll n)
{
    for(int i=0;i<=n;i++)
    {
        if(a[i]==k) return 1;
    }
    return 0;
}
int main()
{
    ll n;
    cin>>n;
    ll a[n+1];
    memset(a,0,n+1);
    a[1]=1;
    a[2]=1;
    if(n<=3)
    {
        for(int i=0;i<n;i++)cout<<"O";
        return 0;
    }
    for(int i=3;i<=n+1;i++)
    {
        a[i]=a[i-1]+a[i-2];
        // cout<<a[i]<<endl;
    }

    for(int i=1;i<=n;i++)
    {
        if(is_fib(i,a,n))cout<<"O";
        else cout<<"o";

    }

    return 0;
}


//https://codeforces.com/contest/918/problem/A
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    ll n;
    cin>>n;

    ll a[n+1];
    a[1]=1;a[2]=1;
    ll fib[n+1];

    memset(fib,0,n+1);
    fib[1]=1;fib[2]=1;
    for(ll i=3;i<=n;i++)
    {
        a[i]=a[i-1]+a[i-2];
        if(a[i]<=n)
        {fib[a[i]]=1;}

        else break;
    }
    // cout<<"e";
    string st="";
    for(ll i=1;i<=n;i++)
    {
        if(fib[i]==1)st=st+'O';
        else st=st+'o';
    }
    cout<<st;
    return 0;
}


//https://codeforces.com/contest/918/problem/A
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int is_fib(int k,int f[],int n)
{
    for(int i=1;i<=n;i++)
    {
        if(k==f[i]) return 1;
    }
    return 0;
}
int main()
{

   int n;
   cin>>n;
   if(n==1)
   {
       cout<<"O";
       return 0;
   }
   if(n==2)
   {
       cout<<"OO";
       return 0;
   }
   if(n==3)
   {
       cout<<"OOO";
       return 0;
   }
   int f[n+1];
   memset(f,0,n+1);
   f[1]=1;
   f[2]=1;
   for(int i=3;i<=n;i++)
   {
       f[i]=f[i-1]+f[i-2];
    //    cout<<f[i]<<endl;
        if(f[i]>n-1) break;
   }
    cout<<"OOO";
    for(int i=4;i<=n;i++)
    {
        if(is_fib(i,f,n))cout<<"O";
        else cout<<"o";
    }

    return 0;
}


//https://codeforces.com/contest/918/problem/A
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int n;
    cin>>n;

    int a[n+1];
    a[1]=1;a[2]=1;
    int fib[n+1];

    memset(fib,0,n+1);
    fib[1]=1;fib[2]=1;
    for(int i=3;i<=n;i++)
    {
        a[i]=a[i-1]+a[i-2];
        if(a[i]<=n)fib[a[i]]=1;
    }
    // cout<<"e";
    string st="";
    for(int i=1;i<=n;i++)
    {
        if(fib[i]==1)st=st+'O';
        else st=st+'o';
    }
    cout<<st;
    return 0;
}


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

int main()
{
    int t1 = 0, t2 = 1, nextTerm = 0, n;

    cin >> n;

    int arr[n];
    arr[0]=t1;
    arr[1]=t2;
   int i=2;
    while(nextTerm <= n)
    {

        t1 = t2;
        t2 = nextTerm;
        nextTerm = t1 + t2;
        arr[i]=t1+t2;
        i++;
    }

    char s[n];

    for(int j=0;j<n;j++){
        s[j]='o';
    }

    for(int j=0;j<=i;j++){
        s[arr[j]]='O';
    }
     for(int j=0;j<n;j++){
       cout<<s[j];
    }

    return 0;
}