Newcoder 140 J.farm(二维前缀和)

186 篇文章 0 订阅

Description

给一个 n×m n × m 的矩阵 ai,j a i , j T T 次操作,每次操作把一个子矩阵[x1,x2]×[y1,y2]中不等于 k k 的数字删掉,一个数字只会被删掉一次,问操作结束后该矩阵中被删掉的数字个数

Input

第一行一整数n,m,T,之后输入一个 n×m n × m 矩阵,最后 T T 行每行输入五个整数x1,y1,x2,y2,k

(nm106,T106,1ai,j,knm) ( n ⋅ m ≤ 10 6 , T ≤ 10 6 , 1 ≤ a i , j , k ≤ n ⋅ m )

Output

输出被删掉的数字个数

Sample Input

2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1

Sample Output

3

Solution

考虑数字只有 0,1 0 , 1 的情况,只需用二维前缀和维护一个位置被加的 1 1 的数量和0的数量,如果该位置为 x x 且被加入1x的数量非 0 0 则该位置记入答案,而对于数字不超过106的情况,分 29 29 位分别考虑即可,只要有一位有变动则该位置的值发生变化

Code

#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 1000005
int n,m,T,g[maxn],first[maxn],tot[maxn],a1[maxn],b1[maxn],a2[maxn],b2[maxn],k[maxn],vis[maxn];
int ID(int x,int y)
{
    if(x==0||y==0)return 0;
    return (x-1)*m+y;
}
void update(int a1,int b1,int a2,int b2,int *a)
{
    a[ID(a1,b1)]++;
    if(b2<m)a[ID(a1,b2+1)]--;
    if(a2<n)a[ID(a2+1,b1)]--;
    if(b2<m&&a2<n)a[ID(a2+1,b2+1)]++;
}
void sum(int *a)
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[ID(i,j)]+=(a[ID(i-1,j)]+a[ID(i,j-1)]-a[ID(i-1,j-1)]);
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&T))
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&g[ID(i,j)]);
        memset(tot,0,sizeof(tot));
        for(int i=1;i<=T;i++)
        {
            scanf("%d%d%d%d%d",&a1[i],&b1[i],&a2[i],&b2[i],&k[i]);
            update(a1[i],b1[i],a2[i],b2[i],tot);
        }
        sum(tot);
        memset(vis,0,sizeof(vis));
        for(int s=0;s<20;s++)
        {
            memset(first,0,sizeof(first));
            for(int i=1;i<=T;i++)
                if((k[i]>>s)&1)
                    update(a1[i],b1[i],a2[i],b2[i],first);
            sum(first);
            for(int i=1;i<=n*m;i++)
                if((g[i]>>s)&1)
                {
                    if(first[i]!=tot[i])vis[i]=1;
                }
                else if(first[i])vis[i]=1;
        }
        int ans=0;
        for(int i=1;i<=n*m;i++)ans+=vis[i];
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值