NKOJ-4224 矩阵计数

P4224矩阵计数
时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 1s
问题描述

给出一个n*m的方格矩阵,每个格子里都有一个整数。你有两种操作:
"1 x y k" 将坐标为x,y的格子的数字改为k;
"2 x1 y1 x2 y2 k"询问满足值为k且坐标(x,y)  x1<=x<=x2  ,y1<=y<=y2的格子的数量

输入格式

第一行,两个整数n和m
接下来一个n*m的整数矩阵,表示矩阵的初始情况。
接下来一行,一个整数Q,表示有Q个操作:
操作1:"1 x y k" 将坐标为x,y的格子的数字改为k;
操作2:"2 x1 y1 x2 y2 k"询问满足值为k且坐标x1<=x<=x2  ,y1<=y<=y2的格子的数量

输出格式

对于每个2号操作,输出一行,一个整数,表示查询结果

样例输入 1

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

样例输出 1

1
2

样例输入 2

5 5
4 3 4 5 3 
2 5 4 1 3 
5 2 3 4 4 
2 5 3 3 3 
5 1 1 1 3 
6
2 1 1 5 3 1
1 2 2 2
1 2 3 4
2 2 1 5 3 2
1 4 4 2
2 1 1 3 5 2

样例输出 2

2
4
3

提示

对于30%的数据:n,m<=30     Q<=5000
对于100%的数据:
n,m<=300    Q<=200000     k<=100  
1<=x,x1,x2<=n     1<=y,y1,y2<=m        x1<=x2       y1<=y2

来源 改编自jsoi2009 count

由于这道题目太过于直接,没有任何剧情,所以我也没啥好吐槽的…

题解

思路

这道题目的解法其实很暴力
我们知道在某一个二维矩阵里头增加标记1时的操作和计数,就是使用二维树状数组
那么如何在一个二维矩阵当中增加某一个数字的标记呢??
我们就多开一维嘛
我们给每一个数字开一个二维矩阵,当原矩阵当中的某个位置是某个数字时,我们就在该数字的矩阵的相应位置标个1
例如

1 2 3
4 5 6
1 2 3

那么对应的数字1的矩阵为
1 0 0
0 0 0
1 0 0
对应数字5的矩阵为
0 0 0
0 1 0
0 0 0

这个样子,我们就能够轻易地进行改动,操作与二维树状数组的修改和统计操作基本相同

注意

我们在修改某个位置的数字时,要先将该位置的原数字标记取消掉,在添加新的标记

例如

原矩阵
1 2 3
3 2 1
我们将3 1上的数字3修改为1
那么
    3的矩阵将由
        0 0 1
        1 0 0
    变为
        0 0 0
        1 0 0

    1的矩阵将由
        1 0 0
        0 0 1
    变为
        1 0 1
        0 0 1

不懂二维树状数组操作的请自行百度…确实讲起很麻烦

附上代码

#include <iostream>
#include <cstdio>
using namespace std;

int n,m;
int maps[345][345],C[123][312][312];

inline int input()
{
    char c=getchar();int o;
    while(c>57||c<48)c=getchar();
    for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;
    return o;
}

int lowbit(int x){return x&-x;}

void add(int x,int y,int num,int d)
{
    for(int a=x;a<=n;a+=lowbit(a))
    for(int b=y;b<=m;b+=lowbit(b))
        C[num][a][b]+=d;
}

int sum(int x,int y,int num)
{
    int ans=0;
    for(int a=x;a;a-=lowbit(a))
    for(int b=y;b;b-=lowbit(b))
        ans+=C[num][a][b];
    return ans;
}

int main()
{
    int xo,yo,xt,yt,num,t,q;
    n=input();m=input();
    for(int x=1;x<=n;x++)
    for(int y=1;y<=m;y++)
    {
        maps[x][y]=input();
        add(x,y,maps[x][y],1);
    }
    t=input();
    for(int i=1;i<=t;i++)
    {
        q=input();
        if(q==2)
        {
            xo=input()-1;yo=input()-1;xt=input();yt=input();num=input();
            printf("%d\n",sum(xt,yt,num)+sum(xo,yo,num)-sum(xo,yt,num)-sum(xt,yo,num));
        }
        else
        {
            xo=input();yo=input();num=input();
            add(xo,yo,maps[xo][yo],-1);
            maps[xo][yo]=num;
            add(xo,yo,num,1);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值