题意: 简化就是有两种操作,一种是插入(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. poj3358:欧拉定理

    又是一道用欧拉定理解的题..嗯,关键还是要建好方程,注意一些化简技巧 题目大意: 给定一个由 p / q 生成的循环小数,求此循环小数在二进制表示下的最小循环节以及不是循环节的前缀 思路: 小数化为二 ...

  2. PHP关于时区问题

    最近在学习PHP过程中发现PHP中的格式化时间戳比北京时间晚了8个小时,上网搜索发现原来是时区不对,解决办法是:      1.永久修改           更改php.ini文件中的data.tim ...

  3. jquery href属性和click事件冲突

    a标签的定义如下: <a href="javascript:void(0);">test</a> jquery中的click事件: $("a&qu ...

  4. Entify Framewrok - LINQ简单使用

    1.如何使用Join: http://www.devcurry.com/2011/01/join-example-in-linq-and-c.html

  5. zoj 3811 Untrusted Patrol(bfs或dfs)

    Untrusted Patrol Time Limit: 3 Seconds      Memory Limit: 65536 KB Edward is a rich man. He owns a l ...

  6. python入门第一天,循环与判断

    学习一门新的语言最重要的就是练习. 一.脚本需求: 编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 二.脚本流程图: 写代码之前画个流程图总是好的,可以让你理清思路,避免写着写着 ...

  7. (转)iOS Wow体验 - 第二章 - iOS用户体验解析(2)

    本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第二章译文精选的第二部分,其余章节将陆续放出.上一 ...

  8. Windows使用WxWidgets开发界面(c++)环境搭建

    一直想学习wxWidgets,之前使用的都是wxPython,现在终于鼓起勇气学习这个了,发现原来是基于vc6.0开发的.所以最好的学习办法就是安装vistual studio 2010,方便学习看代 ...

  9. 如何判断Linux load的值是否过高

    1.先使用top看下CPU占用高的进程,找出进程的进程ID(pid): 查看方法:top 2.根据进程ID(pid)查看是进程的那些线程占用CPU高. 查看方法:top -Hp pid 3.使用pst ...

  10. ASP.Net MVC与WebForm的区别