NOI 模拟试题(一)

                         智子入侵

【题目背景】
三体发现了人类。
在疲于应付三个无法预测规律的太阳的时候,地球是他们唯一的希望。
为了限制住人类的基础物理研究,避免 300 年的技术爆炸,智子到达了地球。
目标:所有的粒子对撞机。
【题目描述】
作为三体人的科学执政官,元首需要你想他汇报智子每一次攻击的成果。军事执政官
已经把智子的攻击计划提交给你,而人类的一举一动也在智子的监视之下。你需要计算出
每一次智子的攻击能够摧毁多少个对撞机。
把地球的地面抽象为一个网格平面,对撞机占据一块边界与坐标轴平行的矩形地面,
而智子每次只攻击一个格子。一个对撞机的任意一部分被攻击到,则整个对撞机被彻底摧
毁。
需要注意的是,对撞机之间可以重叠。
【输入】(collider.in)
文件的第一行有一个正整数 n,表示你所知道的 n 个事件。接下来的 n 行描述 n 个事
件(它们按输入的顺序依次发生)。事件只有两种:Build & Destroy(B & D)。
第 i+1 行(i>=1)描述了第 i 个事件,每一行的开头是一个字母,表示事件的种类,格
式如下:
B x1 y1 x2 y3:建造一个对撞机,左下角坐标为(x1,y1),右上角坐标为(x2,y2)
D x1 y1:智子进行了一次攻击,坐标为(x1,y1)
注意,坐标均为正整数。B 和 D 为大写。
【输出】(collider.out)
对于每一次智子的攻击,在单独的一行里输出这一次攻击摧毁掉的对撞机个数。
【样例输入】
4
B 1 1 3 3
B 3 3 5 5
D 3 3
D 3 3
【样例输出】
2
0
【数据规模】
25%的数据 n<=1000 x,y<=500
50%的数据 n<=10000 x,y<=500
100%的数据 n<=200000 x,y<=1500

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=200010,M=1510,K=25000010;
struct Data
{
    int tp,x1,y1,x2,y2;
} q[N];
int cnt,rt[M<<2],ch[K][2],Min[K];
int Q,ans[N];
char tp[10];
#define mid ((l+r)>>1)

int NewNode()
{
    Min[++cnt]=K;
    return cnt;
}

void Inserty(int &x,int l,int r,int gy,int key)
{
    if(!x)x=NewNode();
    if(l==r)
    {
        Min[x]=min(Min[x],key);
        return;
    }
    if(mid>=gy)Inserty(ch[x][0],l,mid,gy,key);
    else Inserty(ch[x][1],mid+1,r,gy,key);
    Min[x]=min(Min[ch[x][0]],Min[ch[x][1]]);
}

void Insertx(int x,int l,int r,int gx,int gy,int key)
{
    Inserty(rt[x],1,1500,gy,key);
    if(l==r)return;
    if(mid>=gx)Insertx(x<<1,l,mid,gx,gy,key);
    else Insertx(x<<1|1,mid+1,r,gx,gy,key);
}

int Queryy(int x,int l,int r,int y1,int y2)
{
    if(!x)return K;
    if(l>=y1&&r<=y2)return Min[x];
    int ret=K;
    if(mid>=y1)ret=min(ret,Queryy(ch[x][0],l,mid,y1,y2));
    if(mid<y2)ret=min(ret,Queryy(ch[x][1],mid+1,r,y1,y2));
    return ret;
}

int Queryx(int x,int l,int r,int x1,int x2,int y1,int y2)
{
    if(l>=x1&&r<=x2)return Queryy(rt[x],1,1500,y1,y2);
    int ret=K;
    if(mid>=x1)ret=min(ret,Queryx(x<<1,l,mid,x1,x2,y1,y2));
    if(mid<x2)ret=min(ret,Queryx(x<<1|1,mid+1,r,x1,x2,y1,y2));
    return ret;
}

int main()
{
    freopen("collider.in","r",stdin);
    freopen("collider.out","w",stdout);
    scanf("%d",&Q);
    Min[0]=K;
    for(int i=1; i<=Q; i++)
    {
        scanf("%s",tp);
        if(tp[0]=='B')
        {
            q[i].tp=1;
            scanf("%d%d",&q[i].x1,&q[i].y1);
            scanf("%d%d",&q[i].x2,&q[i].y2);
        }
        if(tp[0]=='D')
        {
            q[i].tp=2;
            scanf("%d%d",&q[i].x1,&q[i].y1);
        }
    }
    for(int i=Q; i>=1; i--)
    {
        if(q[i].tp==2)
            Insertx(1,1,1500,q[i].x1,q[i].y1,i);
        else
        {
            int ret=Queryx(1,1,1500,q[i].x1,q[i].x2,q[i].y1,q[i].y2);
            if(ret!=K)ans[ret]+=1;
        }
    }
    for(int i=1; i<=Q; i++)
        if(q[i].tp==2)
            printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值