题意: 简化就是有两种操作,一种是插入(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. hdu5024-Wang Xifeng's Little Plot

    此题一开始用暴力做,后来发现斜着走的时候其实暴力不太好写,于是改用搜索写了 #include <iostream> #include <stdio.h> #include &l ...

  2. Codeforce 217 div2

    C 假设每种颜色的个数都相同,可以用轮换的方式,让答案达到最大n,当不同的时候,可以每次从每种颜色中取出相同个数的手套来操作; 一直迭代下去直到只剩下1种颜色; 再将这一种颜色与之前交换过的交换就行了 ...

  3. poj 1274 The Perfect Stall(二分图匹配)

    Description Farmer John completed his new barn just last week, complete with all the latest milking ...

  4. autoitv3点击windows界面

    在自动化测试过程中会遇到如下windows安全认证,需要输入账号和密码,这个认证对话框不属于element元素.无法用selenium操作,需要用autoitv3操作,输入账号密码后,再进行web元素 ...

  5. IE8下载按钮失效

    <input id="Button1" class="btn-lg-gary" type="button" onclick=" ...

  6. EClipse开发NDK流程

    EClipse开发NDK流程(现在studio也在2.2之后支持了非常简单,只要创建项目的时候勾选c++支持就可以了)   什么情况下使用ndk,1.保护代码,java很容易反编译,c/c++反汇编比 ...

  7. .NET踩坑记录【不断更新】

    NET 4.0 Tasks 使用 ThreadPool 可设置最大并发级别. 多个WebClient多线程下载受System.Net.ServicePointManager.DefaultConnec ...

  8. C#设置textboox只能输入数字`

    1.在闪电KeyPress事件中添加 private void textBox_pwmx_fre_KeyPress(object sender, KeyPressEventArgs e) { //如果 ...

  9. Java菜鸟学习笔记--面向对象篇(十五):Wrapper Class包装类

    什么是包装类? 在Java里一切都是对象,除了Java中的基本数据类型(byte,short,int,long,char,float,double,boolean)不是面向对象的,这在实际使用时存在很 ...

  10. 关于页面刷新或者调用方法事获取不到元素信息或者出现缺少对象错误的换位思考setTimeout的使用

    这两天客户的需求不能定下来,做闲人好长时间了,不如来整理下最近碰到的一些个小麻烦. 正题: 场景一. 最近在开发的过程中使用到了百度的富客户端文本编辑器(ueditor)---这是一款功能很强大的文本 ...