AGC015C Nuske vs Phantom Thnook

题意简述:给定一个\(N*M(N,M<=2000)\)的矩阵,有黑白两种颜色,保证每个色块为一棵树。即如果块的大小为\(N\),那么块内公共边数为\(N-1\)。有\(q(q<=2*10^5)\)次询问,每次询问一个矩阵内有多少个联通块。

一开始搞矩阵内树的定义搞了好久。。

然后我们发现由于一棵树点数减去边数为1,那么我们只要记录点,边的二维前缀和,拿给定矩阵内的总点数减去总边数即为答案。

然后我敲了一发,发现样例都不能过。

debug了一手,发现我好想边的二维前缀和相减时,少减了边界上的。。。

然后想了一想,发现不大会处理。

于是去orz了一波yls博客,把行列分开记录就ok了。

这种题没自己做出来实在有点不应该。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2010;
int sum_v[N][N],sum_l[N][N],sum_r[N][N];
int n,m,q;
char s[N][N];
int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;j++)
            if(s[i][j]=='1'){
                sum_v[i][j]=1;
                if(s[i][j-1]=='1')sum_l[i][j]=1;
                if(s[i-1][j]=='1')sum_r[i][j]=1;
            }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            sum_v[i][j]+=sum_v[i-1][j]+sum_v[i][j-1]-sum_v[i-1][j-1];
            sum_l[i][j]+=sum_l[i-1][j]+sum_l[i][j-1]-sum_l[i-1][j-1];
            sum_r[i][j]+=sum_r[i-1][j]+sum_r[i][j-1]-sum_r[i-1][j-1];
        }
    while(q--){
        int x=read(),y=read(),xx=read(),yy=read();
        int ans=sum_v[xx][yy]-sum_v[x-1][yy]-sum_v[xx][y-1]+sum_v[x-1][y-1];
        ans-=sum_l[xx][yy]-sum_l[x-1][yy]-sum_l[xx][y]+sum_l[x-1][y];
        ans-=sum_r[xx][yy]-sum_r[x][yy]-sum_r[xx][y-1]+sum_r[x][y-1];
        printf("%d\n",ans);
    }
}

posted @ 2019-04-15 20:05  努力进步的肥宅yxc  阅读(154)  评论(0编辑  收藏  举报