抓企鹅

抓企鹅

时间限制: 2 Sec 内存限制: 256 MB

题目描述
Xyz带着他的教徒们乘着科考船一路破冰来到了南极大陆,发现这里有许许多多的企鹅。邪恶的Xyz想要抓很多企鹅回去开动物园,当宠物玩。但动物保护协会很快赶来,他必须尽快行动!
  我们把南极大陆看成一个三维直角坐标系。
  有N只企鹅,每只企鹅会在一定的时刻的出现,第i只企鹅在Ai时刻出现在坐标为(Bi,Ci,Di)的地方。
  Xyz要在某一时刻在某一地方(X,Y,Z)撒一张大网,将(0,0,0)到(X,Y,Z)这个大长方体里的企鹅全都网进去捕捉回家(还没出现的企鹅就不会被捉进去了)。
  为了快准狠而且保证不铺张浪费网,Xyz想知道不同时间不同地点撒网能抓到几个企鹅(这样的询问有Q个)。然后他再行动。

输入
第一行一个整数N表示企鹅个数。
第二行到N+1行每行四个实数(Ai,Bi,Ci,Di),表示企鹅的出现时间和位置
第N+2行一个整数Q表示询问个数。
接下来Q行每行四个实数(T,X,Y,Z),表示询问的时间和位置。

输出
输出共Q行,每行一个整数,回答每个询问能抓到几个企鹅。

样例输入
1
0 0 0 0
2
1 1 1 1.0
1 1 1 -1

样例输出
1
0

【数据规模和约定】
共20个数据
数据1~3 N,Q<=1000
数据4~6 N,Q<=5000
数据7~10 N,Q<=10000
数据11~14 N<=30000,Q<=10000
数据15~18 N<=10000,Q<=30000
数据19~20 N,Q<=30000

题解

分治套分治套树状数组,分别维护x坐标,y坐标,z坐标。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define N 30010
using namespace std;
int n,m,Tnum,C[N*2],ans[N];
double h[N*2],num[N*2];
struct node{
  int type,pos,c;double x,a,b;
  bool operator<(const node &wbs)const{
    if(x!=wbs.x)return x<wbs.x;
    if(a!=wbs.a)return a<wbs.a;
    if(b!=wbs.b)return b<wbs.b;
    if(c!=wbs.c)return c<wbs.c;
    return type<wbs.type;
  }
}t[N*2],tp[N*2],p[N*2];

class bit
{
  public:
  void modify(int x,int val)
  {
    for(;x<=Tnum;x+=x&-x)C[x]+=val;
  }
  int qry(int x)
  {
    int res=0;
    for(;x;x-=x&-x)res+=C[x];
    return res; 
  }
}T;

void solve2(int l,int r)
{
  if(l==r)return;
  int mid=l+r>>1,lx=l,rx=mid+1,tot=0;
  solve2(l,mid);solve2(mid+1,r);
  while(rx<=r)
  {
    if(lx<=mid&&tp[lx].b<=tp[rx].b)
    {
      if(!tp[lx].type)T.modify(tp[lx].c,1);
      p[++tot]=tp[lx];lx++;
    }
    else
    {
      if(tp[rx].type)ans[tp[rx].pos]+=T.qry(tp[rx].c);
      p[++tot]=tp[rx];rx++; 
    } 
  }
  for(int i=l;i<lx;i++)
    if(!tp[i].type)T.modify(tp[i].c,-1);
  while(lx<=mid)p[++tot]=tp[lx],lx++;
  for(int i=l;i<=r;i++)tp[i]=p[i-l+1];
}

void solve(int l,int r)
{
  if(l==r)return;
  int mid=l+r>>1,lx=l,rx=mid+1,tot=0,num=0;
  solve(l,mid);solve(mid+1,r);
  while(rx<=r)
  {
    if(lx<=mid&&t[lx].a<=t[rx].a)
    {
      if(!t[lx].type)tp[++num]=t[lx];
      p[++tot]=t[lx];lx++;
    }
    else
    {
      if(t[rx].type)tp[++num]=t[rx];
      p[++tot]=t[rx];rx++; 
    } 
  }
  while(lx<=mid)p[++tot]=t[lx],lx++;
  for(int i=l;i<=r;i++)t[i]=p[i-l+1];
  if(num)solve2(1,num);
}

int main()
{
  double x,a,b,c;
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
  { 
    scanf("%lf%lf%lf%lf",&x,&a,&b,&c);
    t[i]=(node){0,0,0,x,a,b};h[i]=c;num[i]=c;
  }
  scanf("%d",&m);
  for(int i=1;i<=m;i++)
  { 
    scanf("%lf%lf%lf%lf",&x,&a,&b,&c);
    t[i+n]=(node){1,i,0,x,a,b};h[i+n]=c;num[i+n]=c;
  }
  n+=m;sort(h+1,h+n+1);
  Tnum=unique(h+1,h+n+1)-h-1;
  for(int i=1;i<=n;i++)
    t[i].c=lower_bound(h+1,h+Tnum+1,num[i])-h;
  sort(t+1,t+n+1);

  solve(1,n);
  for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 
  return 0; 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值