玩具积木(二维树状数组)

题目背景

wzt在家里的地板上玩一套神犇牌积木

题目描述

由于wzt家并不是无穷大的,所以地板只有n×m个单位大,且恰好由n×m个1× 1的小格子组成。以整个地板左上角的格子作为原点(坐标为(1,1)),wzt会将p块积木随意的抛出落在地板上。积木是一个长方体(此题中认为所有积木的高均为1),保证积木落地时积木底面端点恰好落在格点上,底面棱恰好与小格子的边重合(通俗的说就是不会斜着落在地板上)

神犇牌积木的边具有极强的不会消除的黏性,即当一个积木落下碰到另一个物体后,其位置不会再改变。如下图所示

Luogu

这种情况下,上方积木也不会斜着落下接触地面

就在wzt抛完了所有积木后,lsq突然来到他家。lsq突然问wzt

lsq:(用手一指)那个坐标上有几个积木?

wzt:……(数一数)5

lsq:(用手一指)那个坐标上有几个积木?

wzt:……(数一数)8

lsq:(用手一指)那个坐标上有几个积木?

wzt:………你怎么那么多问题……

lsq:不多啊,就q个而已。

wzt:………………

wzt对此感到很头疼,lsq的问题太多了。于是他请求于AK过NOI的你帮他写一个程序解决这个问题

输入输出格式

输入格式:

第一行有两个数n,m,表示地板的大小

第二行有两个数p,q,表示p个积木和q个询问

接下来(p+q)行

前p行为p个积木的落地点,后q行为q个来自lsq的询问

格式:

a b x y:表示积木静止后左上端点为(a,b),右下端点为(x,y)

i j:表示lsq询问坐标为(i,j)的格子上有几个积木

输出格式:

输出共q行,为lsq的询问的答案

输入输出样例

输入样例#1:  复制
5 5
2 3
1 1 3 3
2 2 3 3
1 1
2 2
3 3
输出样例#1:  复制
1
2
2






说明

样例解释:

地毯可抽象成下图

保证所有积木的坐标均不超出地板范围,保证所有的ai<=xi,bi<=yi

对于30%的数据,n,m<=100,p,q<=500

对于60%的数据,n,m<=1000,p,q<=1000

对于100%的数据,n,m<=4000,p,q<=100000

//图片和题目均取自洛谷比赛点击打开链接

我们观察题目范围发现可以用暴力来骗取部分分直接暴力枚举就可以

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
int ans[9000][9000],n,m,p,q;
using namespace std;
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%d%d",&p,&q);
    for(int i=1;i<=p;i++)
    {
        int a,b,x,y;
        scanf("%d%d%d%d",&a,&b,&x,&y);
        for(int i=a;i<=x;i++)
        {
            for(int j=b;j<=y;j++)
            {
                ans[i][j]++;
            }
        }
    }
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",ans[x][y]);
    }
    return 0;
 } 

然后我们可以用树状数组来维护这个n,m矩阵

主要就是二维树状数组的区间修改和单点查询:

1.区间修改:直接容斥原理就好了;

2.单点查询:和一维树状数组一样;

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define lowbit(x) x&-x 
using namespace std;
int num[4005][4005],n,m,p,q,x1,x2,y1,y2;
void Add_Num(int x,int y,int k)
{
	for(int i=x;i<=n;i+=lowbit(i))
		for(int j=y;j<=m;j+=lowbit(j))
		   num[i][j]+=k;
}
int Query(int x,int y)
{
	int ans=0;
	for(int i=x;i>0;i-=lowbit(i))
		for(int j=y;j>0;j-=lowbit(j))
		   ans+=num[i][j];
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%d%d",&p,&q);
	for(int i=1;i<=p;i++)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		Add_Num(x1,y1,1);//容斥原理,
		Add_Num(x2+1,y1,-1);
		Add_Num(x1,y2+1,-1);
		Add_Num(x2+1,y2+1,1);
	 } 
	 for(int i=1;i<=q;i++)
	 {
	 	int x,y;
	 	scanf("%d%d",&x,&y);
	 	printf("%d\n",Query(x,y)); 
	 }
	 return 0;
 } 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值