In his spare time Vladik estimates beauty of the flags.
Every flag could be represented as the matrix n × m which consists of positive integers.
Let's define the beauty of the flag as number of components in its matrix. We call component a set of cells with same numbers and between any pair of cells from that set there exists a path through adjacent cells from same component. Here is the example of the partitioning some flag matrix into components:
But this time he decided to change something in the process. Now he wants to estimate not the entire flag, but some segment. Segment of flag can be described as a submatrix of the flag matrix with opposite corners at (1, l) and (n, r), where conditions 1 ≤ l ≤ r ≤ m are satisfied.
Help Vladik to calculate the beauty for some segments of the given flag.
First line contains three space-separated integers n, m, q (1 ≤ n ≤ 10, 1 ≤ m, q ≤ 105) — dimensions of flag matrix and number of segments respectively.
Each of next n lines contains m space-separated integers — description of flag matrix. All elements of flag matrix is positive integers not exceeding 106.
Each of next q lines contains two space-separated integers l, r (1 ≤ l ≤ r ≤ m) — borders of segment which beauty Vladik wants to know.
For each segment print the result on the corresponding line.
4 5 4 1 1 1 1 1 1 2 2 3 3 1 1 1 2 5 4 4 5 5 5 1 5 2 5 1 2 4 5
6 7 3 4
Partitioning on components for every segment from first test case:
分析:n很小不超過10,考慮直接上線段樹,線段樹上的每個點上保存當前這個線段的左右兩端的連通性,每次兩個線段合併時用並查集就可以了,我寫合併操作時用了面向沒有對象的思想,把合併操作作爲線段類的一個方法,雖然似乎並沒有什麼卵用。
#include<bits/stdc++.h>
#define N 15
#define M 100005
using namespace std;
int n,m,x,y,q,cnt,fa[N*M],a[N][M];
int Find(int x)
{
if(fa[x] == x) return x;
fa[x] = Find(fa[x]);
return fa[x];
}
struct segment
{
int l[N],r[N],tot;
void _merge(segment ls,segment rs,int k)
{
for(int i = 1;i <= n;i++)
{
fa[ls.l[i]] = ls.l[i];
fa[ls.r[i]] = ls.r[i];
fa[rs.l[i]] = rs.l[i];
fa[rs.r[i]] = rs.r[i];
}
tot = ls.tot + rs.tot;
for(int i = 1;i <= n;i++)
if(a[i][k] == a[i][k+1])
{
int al = Find(ls.r[i]),ar = Find(rs.l[i]);
if(al != ar)
{
tot--;
fa[al] = ar;
}
}
for(int i = 1;i <= n;i++) l[i] = Find(ls.l[i]),r[i] = Find(rs.r[i]);
}
}tr[4*M];
void Build(int i,int l,int r)
{
if(l == r)
{
for(int j = 1;j <= n;j++)
if(a[j][l] != a[j-1][l]) tr[i].l[j] = tr[i].r[j] = ++cnt,tr[i].tot++;
else tr[i].l[j] = tr[i].r[j] = tr[i].l[j-1];
return;
}
int mid = (l+r)>>1;
Build(2*i,l,mid);
Build(2*i+1,mid+1,r);
tr[i]._merge(tr[2*i],tr[2*i+1],mid);
}
segment Query(int i,int l,int r,int x,int y)
{
if(l == x && r == y) return tr[i];
int mid = (l+r)>>1;
if(y <= mid) return Query(2*i,l,mid,x,y);
else
if(x <= mid)
{
segment temp;
temp._merge(Query(2*i,l,mid,x,mid),Query(2*i+1,mid+1,r,mid+1,y),mid);
return temp;
}
else return Query(2*i+1,mid+1,r,x,y);
}
int main()
{
cin.sync_with_stdio(false);
cin>>n>>m>>q;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
cin>>a[i][j];
Build(1,1,m);
for(int i = 1;i <= q;i++)
{
cin>>x>>y;
cout<<Query(1,1,m,x,y).tot<<endl;
}
}