HDU 5126 stars(4维偏序)

7 篇文章 0 订阅
5 篇文章 0 订阅

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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值