题意: 简化就是有两种操作,一种是插入(x,y,z)这个坐标,第二种是查询(x1,y1,z1)到(x2,y2,z2)(x1<=x2,y1<=y2,z1<=z2)的长方体包含多少个点。

解析: 将查询分成8个点,离线做,离散化z值,
两次CDQ,第一次归并排x值,第二次归并排y值,z值用bit树维护更新
查询。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
const int maxn=*;
int N,Q,ans[maxn];
struct node
{
int x,y,z,id,s;//(x,y,z)三维坐标,id编号,s代表状态
node(int x=,int y=,int z=,int id=,int s=)
:x(x),y(y),z(z),id(id),s(s){}
}A[maxn],B[maxn],C[maxn];//A保存原数组,B保存中间过程,C用于归并排序临时数组
bool cmpid(const node& a,const node& b){ return a.id<b.id; } //排id
bool cmpz(const node& a,const node& b){ return a.z<b.z; } //排z值
int tree[maxn];//bit树实现部分
int lowbit(int x){ return x&(-x); }
void Add(int i,int d){ for(;i<maxn;i+=lowbit(i)) tree[i]+=d; }
int Sum(int i)
{
int ret=;
for(;i>;i-=lowbit(i)) ret+=tree[i];
return ret;
}
void CDQ2(int l,int r) //归并排y值,对z值查询更新
{
if(l>=r) return;
int mid=(l+r)/;
CDQ2(l,mid);
CDQ2(mid+,r);
int ls=l,rs=mid+;
while(rs<=r)
{
while(ls<=mid&&B[ls].y<=B[rs].y) //选取y较小的
{
if(B[ls].s==) Add(B[ls].z,); //如果是0则需要插入bit树
ls++;
}
if(B[rs].s!=) ans[B[rs].id]+=Sum(B[rs].z)*B[rs].s; //右边的是查询
rs++;
}
while(ls>l) //恢复
{
ls--;
if(B[ls].s==) Add(B[ls].z,-);
}
ls=l,rs=mid+;
for(int i=l;i<=r;i++) //归并排序过程,排y值
{
if((ls<=mid&&B[ls].y<=B[rs].y)||rs>r) C[i]=B[ls++];
else C[i]=B[rs++];
}
for(int i=l;i<=r;i++) B[i]=C[i];
}
void CDQ1(int l,int r)//归并排x值,选取的过程是时序
{
if(l==r) return;
int mid=(l+r)/;
CDQ1(l,mid);
CDQ1(mid+,r);
int ls=l,rs=mid+,k=;
while(rs<=r)
{
while(ls<=mid&&A[ls].s!=) ls++; //前一半而且是查询不管
while(rs<=r&&A[rs].s==) rs++; //后一半而且是插入不管
if(rs>r) break; //这个地方可能难理解,仔细 想一下如果右边已经没有查询的操作了,
//剩下的左边的时序绝对比最后一次加到B中的查询的操作时序要大
if((A[ls].x<=A[rs].x&&ls<=mid)||rs>r) B[k++]=A[ls++];
else B[k++]=A[rs++];
}
if(k>) CDQ2(,k-); //再一次CDQ
ls=l,rs=mid+;
for(int i=l;i<=r;i++) //归并排序
{
if((ls<=mid&&A[ls].x<=A[rs].x)||rs>r) C[i]=A[ls++];
else C[i]=A[rs++];
}
for(int i=l;i<=r;i++) A[i]=C[i];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
N=;
int type,x1,y1,z1,x2,y2,z2;
scanf("%d",&Q);
while(Q--)
{
scanf("%d",&type);
if(type==)
{
scanf("%d%d%d",&x1,&y1,&z1);
A[N++]=node(x1,y1,z1,N,); //要插入的点
}
else
{
scanf("%d%d%d",&x1,&y1,&z1);
scanf("%d%d%d",&x2,&y2,&z2);
A[N++]=node(x2,y2,z2,N,); //分成8个查询的点
A[N++]=node(x2,y1-,z2,N,-);
A[N++]=node(x1-,y2,z2,N,-);
A[N++]=node(x2,y2,z1-,N,-);
A[N++]=node(x1-,y1-,z2,N,);
A[N++]=node(x1-,y2,z1-,N,);
A[N++]=node(x2,y1-,z1-,N,);
A[N++]=node(x1-,y1-,z1-,N,-);
}
}
memset(ans,,sizeof(ans));
sort(A,A+N,cmpz); //按照z值排序
int ka=;
A[N].z=-;
for(int i=;i<N;i++)
if(A[i].z!=A[i+].z) A[i].z=ka++; //离散化
else A[i].z=ka;
sort(A,A+N,cmpid); //按照时序排回来
memset(tree,,sizeof(tree));
CDQ1(,N-);
sort(A,A+N,cmpid); //再排回来
for(int i=;i<N;i++) //输出答案
{
if(A[i].s==) continue;
int sum=;
for(int j=;j<;j++) sum+=ans[i+j];
printf("%d\n",sum);
i+=;
}
}
return ;
}

Hdu5126-stars(两次CDQ分治)的更多相关文章

  1. 胡扯两句——CDQ分治

    之前听大神讲过CDQ分治大概是个什么东西,但是一直还没有真正去搞过.今天稍微看了一下,写点自己的理解. 首先CDQ分治有两个条件. 条件1:可以分成两个独立互不影响的问题(这里的"独立&qu ...

  2. 【Luogu1393】动态逆序对(CDQ分治)

    [Luogu1393]动态逆序对(CDQ分治) 题面 题目描述 对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i < j的有序对(i,j)的个数.你需要计算出一个序 ...

  3. cdq分治的小结

    cdq分治 是一种特殊的分治 他的思想: 1.分治l,mid 2.分治mid+1,r 3.计算l,mid对mid+1,r的影响 3就是最关键的地方 这也是cdq的关键点 想到了这一步基本就可以做了 接 ...

  4. 【洛谷3157】[CQOI2011] 动态逆序对(CDQ分治)

    点此看题面 大致题意: 给你一个从\(1\)到\(n\)的排列,问你每次删去一个元素后剩余的逆序对个数. 关于\(80\)分的树套树 为了练树套树,我找到了这道题目. 但悲剧的是,我的 线段树套\(T ...

  5. luogu P3157 [CQOI2011]动态逆序对(CDQ分治)

    题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...

  6. HDU5126 stars【CDQ分治】*

    HDU5126 stars Problem Description John loves to see the sky. A day has Q times. Each time John will ...

  7. HDU5126 stars(CDQ分治)

    传送门 大意: 向三维空间中加点,询问一个三维区间中点的个数. 解题思路: 带修改CDQ,将修改和询问一起插入CDQ分治询问. (询问可以由8个前缀和加减操作实现) 其中第一层CDQ维护x有序. 第二 ...

  8. hdu 5126 stars cdq分治套cdq分治+树状数组

    题目链接 给n个操作, 第一种是在x, y, z这个点+1. 第二种询问(x1, y1, z1). (x2, y2, z2)之间的总值. 用一次cdq分治可以将三维变两维, 两次的话就变成一维了, 然 ...

  9. HDU - 5126 stars (CDQ分治)

    题目链接 题目大意:一共有Q(1<=Q<=50000)组操作,操作分为两种: 1.在x,y,z处添加一颗星星 2.询问以(x1,y1,z1)与(x2,y2,z2)为左上和右下顶点的矩形之间 ...

随机推荐

  1. [iOS] Baritem 添加一项

    不是拖拽,而是在设计栏的属性设置里面.

  2. java之File

    1.文件创建.重命名.删除 code: package com.test; import java.io.File; import java.io.IOException; public class ...

  3. JSON 基本语法

    JSON:JavaScript 对象表示法(JavaScript Object Notation). JSON 是存储和交换文本信息的语法.类似 XML. JSON 比 XML 更小.更快,更易解析. ...

  4. QListWidget方式显示缩略图

    最近在工作中经常遇到了一个问题就是把把文件夹中的图片全部以缩略图的形式显示出来,刚开始的时候一头雾水,不知道怎么办,经过在网上查资料,发现QListWidget控件可以实现图片的缩略图显示,但是不知道 ...

  5. Vue + vue-router

    搞了一天的element-ui,vue-router,把侧栏的导航菜单搞了出来后,试着在菜单上加入链接,研究了下官方提供的文档,发现要使用vue-route. 在项目中安装好vue-route, 对照 ...

  6. Wikioi 1080一维树状数组

    半个月时间最终把那些杂七杂八的学完了,尽管学完也,也仅仅是有了个模板,自己手敲还是不太行.所以如今開始要疯狂刷题了! ! .!!! 这题裸的树状数组.曾经写那道<敌兵布阵>的时候写过,所以 ...

  7. Builder模式 初体验

        看来Java构造器模式,决定动手体验下.构造器模式是什么?干什么用的?推荐大家看下ITEYE的一篇文章     http://www.iteye.com/topic/71175     了解构 ...

  8. JavaScript学习笔记:检测数组方法

    检查数组的方法 很多时候我们需要对JavaScript中数据类型(Function.String.Number.Undefined.Boolean和Object)做判断.在JavaScript中提供了 ...

  9. Entity Framework - Func引起的数据库全表查询

    原文:http://www.cnblogs.com/dudu/archive/2012/04/01/enitity_framework_func.html 使用 Entity Framework 最要 ...

  10. SQL 分组获取最近(大)一条记录

    SELECT MAX( table.Column),.... FROM table.Name WHERE ....... GROUP BY 分组规则