Description
约翰喜欢看天空。 一天有Q次。 每次约翰会在天空中找到一颗新星,或者他想知道(x1,y1,z1)和(x2,y2,z2)之间有多少颗星。
Input
第一行包含一个整数T(1≤T≤10)(小于6的Q> 100的数据),表示测试用例的数量。
第一行包含一个整数Q(1≤Q≤50000),表示一天中有多少次。
接下来Q行包含一些整数,首先输入一个整数A(1≤A≤2)。如果A = 1,则输入3个整数x,y和z,表示一个星的坐标。如果A = 2,则输入6个整数X1,Y1,Z1,X2,Y2,Z2(1≤x,Y,Z,X1,Y1,Z1,X2,Y2,z2≤2^31,x1≤x2,y1≤y2,z1≤z2)。
Output
对于每个“A = 2”,输出一个整数意味着在这个部分中有多少颗星星。
Sample Input
2
11
1 1 1 1
2 1 1 1 1 1 1
1 2 2 2
1 1 1 2
2 1 1 1 2 2 2
1 3 3 3
1 4 4 4
1 5 5 5
1 6 6 6
2 1 1 1 6 6 6
2 3 3 3 6 6 6
11
1 1 1 1
2 1 1 1 1 1 1
1 2 2 2
1 1 1 2
2 1 1 1 2 2 2
1 3 3 3
1 4 4 4
1 5 5 5
1 6 6 6
2 1 1 1 6 6 6
2 3 3 3 6 6 6
Sample Output
1
3
7
4
1
3
7
4
四维偏序模板吧?
1、按时间分治
2、有序合并x轴,重新标记时间,对x轴进行分治
3、三维偏序模板
pts1:对于嵌套cdq,要注意理解的是对于a<b<c<d,当我们操作成(l,b,c,d),(r,b,c,d)之后,我们将三元组(b,c,d)取出,操作成(l,c,d),(r,c,d)后,a的序乱了,这时对l->r的影响要加上之前a的影响来共同判断
pts2:对于立体图形的分割,求体积:(x2-x1)(y2-y1)(z2-z1),因为是线段,注意端点操作即可。
pts3:cdq的操作是自底向上更新的,因此分治cdq(l,r)时,左边的查询操作已经处理好,对右边是毫无贡献的,可以直接忽略。
https://www.cnblogs.com/mlystdcall/p/6232324.html%%%
#include<bits/stdc++.h>
using namespace std;
const int Maxn=500005;
inline int getint(){
int res=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))res=res*10+c-'0',c=getchar();
return res;
}
struct _4D{
int x,y,z,idx,cmd,part;
_4D(int x=0,int y=0,int z=0,int idx=0,int cmd=0,int part=0):
x(x),y(y),z(z),idx(idx),cmd(cmd),part(part){}
}a[Maxn],t[Maxn];
int n,mx,cnt,cntq,f[Maxn];
bool cmp1(const _4D&A,const _4D&B){
return A.x<B.x;
}
bool cmp2(const _4D&A,const _4D&B){
return A.y<B.y;
}
struct BIT{
int c[Maxn];
#define lowbit(x) (x)&-(x)
void add(int x,int k){
for(;x<=mx;x+=lowbit(x))c[x]+=k;
}
int sum(int x){
int ret=0;
for(;x>0;x-=lowbit(x))ret+=c[x];
return ret;
}
}bit;
void cdq2(int l,int r){//x升序
if(l>=r)return ;
int mid=l+r>>1;
cdq2(l,mid),cdq2(mid+1,r);
int i=l,j=mid+1;
for(;j<=r;++j){
for(;i<=mid&&t[i].y<=t[j].y;++i)
if(t[i].part==-1&&t[i].idx==0)bit.add(t[i].z,1);
if(t[j].part==1&&t[j].idx)f[t[j].idx]+=bit.sum(t[j].z)*t[j].cmd;
}
while(--i>=l)if(t[i].part==-1&&t[i].idx==0)bit.add(t[i].z,-1);
inplace_merge(t+l,t+mid+1,t+r+1,cmp2);//严格O(nlogn)?大概
}
void cdq1(int l,int r){
if(l>=r)return ;
int mid=l+r>>1;
cdq1(l,mid),cdq1(mid+1,r);
sort(a+l,a+mid+1,cmp1),sort(a+mid+1,a+r+1,cmp1);
int i=l,j=mid+1,cntt=0;
while(i<=mid&&j<=r){
if(a[i].x<=a[j].x){
t[++cntt]=a[i++];
t[cntt].part=-1;
if(a[i-1].idx)--cntt;
}else {
t[++cntt]=a[j++];
t[cntt].part=1;
if(!a[j-1].idx)--cntt;
}
}
while(i<=mid)t[++cntt]=a[i++],t[cntt].part=-1;
while(j<=r)t[++cntt]=a[j++],t[cntt].part=1;
cdq2(1,cntt);
}
int tmp[Maxn];
void discrete(){
for(int i=1;i<=cnt;++i)
tmp[i]=a[i].z;
sort(tmp+1,tmp+cnt+1);
mx=unique(tmp+1,tmp+cnt+1)-tmp-1;
for(int i=1;i<=cnt;++i)
a[i].z=lower_bound(tmp+1,tmp+mx+1,a[i].z)-tmp;
}
int main(){
int Case=getint();
while(Case--){
cnt=cntq=0;
n=getint();
for(int i=1;i<=n;++i){
int op=getint();
if(op==1){
int x=getint(),y=getint(),z=getint();
a[++cnt]=_4D(x,y,z,0,0,0);
}else {
int x1=getint(),y1=getint(),z1=getint(),x2=getint(),y2=getint(),z2=getint();
a[++cnt]=_4D(x2,y2,z2,++cntq,1,0);
a[++cnt]=_4D(x2,y2,z1-1,cntq,-1,0);
a[++cnt]=_4D(x2,y1-1,z2,cntq,-1,0);
a[++cnt]=_4D(x2,y1-1,z1-1,cntq,1,0);
a[++cnt]=_4D(x1-1,y2,z2,cntq,-1,0);
a[++cnt]=_4D(x1-1,y2,z1-1,cntq,1,0);
a[++cnt]=_4D(x1-1,y1-1,z2,cntq,1,0);
a[++cnt]=_4D(x1-1,y1-1,z1-1,cntq,-1,0);
}
}
discrete();
for(int i=1;i<=cntq;++i)f[i]=0;
cdq1(1,cnt);//操作时间自然有序
for(int i=1;i<=cntq;++i)
cout<<f[i]<<'\n';
}
return 0;
}