同APIO2017 rainbow
只不过这题n,m只用2000,直接数组维护一下然后O(1)询问就可以了
因为任意两个黑点之间最多只有一条路径
那么每个联通块就是一棵树的形式,数的点数减边数是1,所有联通块个数是就是点数减边数
#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 2010
using namespace std;
int n,m,q;
int a[N][N];
int b[N][N],c[N][N];
inline int read(){
char c=getchar();
while(c<'0'||c>'1') c=getchar();
return c-'0';
}
inline int calc(int a[N][N],int x1,int y1,int x2,int y2){
if(x1>x2||y1>y2) return 0;
return a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=read();
for(int i=2;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]=a[i][j]&a[i-1][j];
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
c[i][j]=a[i][j]&a[i][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
b[i][j]=b[i][j]+b[i-1][j]+b[i][j-1]-b[i-1][j-1];
c[i][j]=c[i][j]+c[i-1][j]+c[i][j-1]-c[i-1][j-1];
}
while(q--){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%d\n",calc(a,x1,y1,x2,y2)-calc(b,x1+1,y1,x2,y2)-calc(c,x1,y1+1,x2,y2));
}
}