牛客网暑期ACM多校训练营(第二场) J farm

题目描述 
White Rabbit has a rectangular farmland of n*m. In each of the grid there is a kind of plant. The plant in the j-th column of the i-th row belongs the a[i][j]-th type.
White Cloud wants to help White Rabbit fertilize plants, but the i-th plant can only adapt to the i-th fertilizer. If the j-th fertilizer is applied to the i-th plant (i!=j), the plant will immediately die.
Now White Cloud plans to apply fertilizers T times. In the i-th plan, White Cloud will use k[i]-th fertilizer to fertilize all the plants in a rectangle [x1[i]...x2[i]][y1[i]...y2[i]].
White rabbits wants to know how many plants would eventually die if they were to be fertilized according to the expected schedule of White Cloud.


输入描述:
The first line of input contains 3 integers n,m,T(n*m<=1000000,T<=1000000)
For the next n lines, each line contains m integers in range[1,n*m] denoting the type of plant in each grid.
For the next T lines, the i-th line contains 5 integers x1,y1,x2,y2,k(1<=x1<=x2<=n,1<=y1<=y2<=m,1<=k<=n*m)
输出描述:
Print an integer, denoting the number of plants which would die.

输入
2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1
输出
3

思路:

官方题解之一

先考虑一个特殊的情况:矩形中的数和T次操作放的数都为0或1。 对于这种情况,我们只需要用矩阵前缀和统计一下每个格子被多少个0覆盖,被多少个1覆盖。 如果一个格子的数为0且被放入了至少一个1或这个格子的数位1且被放入了至少一个0则就会对答案产生贡献。
然后考虑原问题。 如果某个格子的数是i,而它被放入了至少一个j,且i!=j,则需要统计进入答案。 注意到,i!=j则i和j至少有一个二进制位不相同。 我们枚举0~19的每一个二进制位,然后把所有数字按照这一位是0还是1划分成两个集合,就变成了上述 特殊情况的问题。一个格子只要至少在某一个二进制位的子问题时被统计进入答案,就加到总答案中去。 复杂度 (nm+T)log(nm)
using namespace std;
typedef long long ll;
const int MAX=1e6+5;
 
int a[MAX],btree[2][MAX],die[MAX],n,m,Q;
 
int num[MAX],x1[MAX],x2[MAX],y11[MAX],y2[MAX]; //询问
int getid(int x,int y) //获得下标
{
    return (x-1)*m+y;
}
void addrect(int *c,int x1,int y1,int x2,int y2) //矩形标记
{
    c[getid(x1,y1)]++;
    if(y2<m) c[getid(x1,y2+1)]--;
    if(x2<n) c[getid(x2+1,y1)]--;
    if(x2<n&&y2<m) c[getid(x2+1,y2+1)]++;
}
void getpresum(int *arr) //处理为前缀和
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(j>1) arr[getid(i,j)]+=arr[getid(i,j-1)];
            if(i>1) arr[getid(i,j)]+=arr[getid(i-1,j)];
            if(i>1&&j>1) arr[getid(i,j)]-=arr[getid(i-1,j-1)];
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n*m;i++)
    {
        scanf("%d",&a[i]);
        btree[0][i]=btree[1][i]=die[i]=0;
    }
     
    for(int i=0;i<Q;i++) scanf("%d%d%d%d%d",&x1[i],&y11[i],&x2[i],&y2[i],&num[i]);
     
    for(int b=0;b<20;b++) //每一位
    {
        for(int i=0;i<Q;i++)
        {
            if(num[i]&1) addrect(btree[1],x1[i],y11[i],x2[i],y2[i]);
            else addrect(btree[0],x1[i],y11[i],x2[i],y2[i]);
            num[i]>>=1; //把下一次的位,移到最低位
        }
        getpresum(btree[0]);
        getpresum(btree[1]);
        for(int i=1;i<=n*m;i++) //统计,恢复
        {
            if(a[i]%2&&btree[0][i] || a[i]%2==0&&btree[1][i]) die[i]=1;
            btree[0][i]=btree[1][i]=0;
            a[i]>>=1;
        }
    }
    int ans=0;
    for(int i=1;i<=n*m;i++) ans+=die[i];
    cout<<ans<<endl;
    return 0;
}

//思想:转化成二进制来做这道题

猜你喜欢

转载自blog.csdn.net/snayf/article/details/81162791