题目链接:https://vjudge.net/problem/HDU-5126
转自:https://blog.csdn.net/qq_24451605/article/details/47040205
题意:在三维空间中输入多个坐标,查询时要求输出在两个坐标间的点的个数。
思路:要离线操作,因此必须加上时间,所以是四维偏序,xyz+时间。把三维坐标转化成三个独立的部分,然后用容斥原理计算。因为要用树状数组,而输入太大,要离散化。注意离散化z必须从1开始,如果是0,那么树状数组add时会死循环。
重复数据可能无法处理。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=5e5+5;
struct NODE
{
int x,y,z,p,t;
NODE() {}
NODE(int _x,int _y,int _z,int _p,int _t):x(_x),y(_y),z(_z),p(_p),t(_t)
{
}
};
NODE star[maxn],star2[maxn],star3[maxn];
int tree[maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int i,int x)
{
while(i<maxn)
{
tree[i]+=x;
i+=lowbit(i);
}
}
int get(int i)
{
int ans=0;
while(i)
{
ans+=tree[i];
i-=lowbit(i);
}
return ans;
}
int res[maxn];
bool compn(NODE a,NODE b)
{
return a.p<b.p;
}
bool compz(NODE a,NODE b)
{
return a.z<b.z;
}
void CDQ2(int l,int r)//对x
{
if(l==r)
return ;
int mid=(l+r)/2;
CDQ2(l,mid);
CDQ2(mid+1,r);
int l1=l,r1=mid+1;
while(r1<=r)
{
while(l1<=mid&&star2[l1].y<=star2[r1].y)
{
if(star2[l1].t==0)
add(star2[l1].z,1);
l1++;
}
if(star2[r1].t!=0)
{
res[star2[r1].p]+=get(star2[r1].z)*star2[r1].t;
}
r1++;
}
while(l1>l)//清空树状数组 memset会超时
{
--l1;
if(star2[l1].t==0)
add(star2[l1].z,-1);
}
l1=l,r1=mid+1;
for(int i=l; i<=r; i++)
{
if((l1<=mid&&star2[l1].y<=star2[r1].y)||r1>r)
star3[i]=star2[l1++];
else
star3[i]=star2[r1++];
}
for(int i=l; i<=r; i++)
star2[i]=star3[i];
}
void CDQ1(int l,int r)//对y
{
if(l==r)
return ;
int mid=(l+r)/2;
CDQ1(l,mid);
CDQ1(mid+1,r);
int l1=l,r1=mid+1,n=0;
while(r1<=r)//每次分治只讨论右半部分与左半部分的关系,不讨论右半部分内部的和左半部分内部的
{
while(star[l1].t!=0&&l1<=mid)//左边的带有标记的不需要管了,因为对于右边计算答案时左边带有标记的不会计算在内
l1++;
while(star[r1].t==0&&r1<=r)//同上,右边不带标记的对答案没有贡献了,只计算右边带有标记的与左边不带有标记的个数多少
r1++;
if(r1>r)
break;
if((star[l1].x<=star[r1].x&&l1<=mid))
star2[n++]=star[l1++];
else
star2[n++]=star[r1++];
}
if(n>0)
CDQ2(0,n-1);
l1=l,r1=mid+1;
for(int i=l; i<=r; i++)//重新排列数组
{
if((star[l1].x<=star[r1].x&&l1<=mid)||(r1>r))
star3[i]=star[l1++];
else
star3[i]=star[r1++];
}
for(int i=l; i<=r; i++)
{
star[i]=star3[i];
}
}
int main()
{
int t,q,a,x1,x2,y1,y2,z1,z2;
scanf("%d",&t);
while(t--)
{
int n=0;
scanf("%d",&q);
while(q--)
{
scanf("%d",&a);
if(a==1)
{
scanf("%d%d%d",&x1,&y1,&z1);
star[n++]=NODE(x1,y1,z1,n,0);
}
else
{
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);//容斥原理
star[n++]=NODE(x2,y2,z2,n,1);
star[n++]=NODE(x2,y1-1,z2,n,-1);
star[n++]=NODE(x1-1,y2,z2,n,-1);
star[n++]=NODE(x2,y2,z1-1,n,-1);
star[n++]=NODE(x1-1,y1-1,z2,n,1);
star[n++]=NODE(x1-1,y2,z1-1,n,1);
star[n++]=NODE(x2,y1-1,z1-1,n,1);
star[n++]=NODE(x1-1,y1-1,z1-1,n,-1);
}
}
memset(res,0,sizeof(res));
sort(star,star+n,compz);
a=1;
star[n].z=-1;
for(int i=0; i<n; i++)//离散化
{
if(star[i].z!=star[i+1].z)
{
star[i].z=a++;
}
else
star[i].z=a;
}
sort(star,star+n,compn);
CDQ1(0,n-1);
sort(star,star+n,compn);
for(int i=0; i<n; i++)
{
if(star[i].t!=0)
{
int ans=0;
for(int j=0; j<8; j++)
{
ans+=res[i+j];
}
printf("%d\n",ans);
i+=7;
}
}
}
return 0;
}