stars [四維偏序] [CDQ套CDQ]

鏈接

HDU 5126
http://acm.hdu.edu.cn/showproblem.php?pid=5126

題意

依次進行q次操作。
操作 1 a b c : 向集合中加入三元組(a,b,c)。
操作 2 a1 b1 c1 a2 b2 c2 : 查詢集合中有多少個三元組(a,b,c)滿足a1<=a<=a2, b1<=b<=b2, c1<=c<=c2。
q<=50000 1<=a,b,c<=10^9

分析

這便是一個四維偏序問題,可以用CDQ套CDQ進行求解。
對查詢操作進行差分,分成8個只查詢前綴的操作。
首先對第一維(即時間維)進行CDQ分治。對於分治區間[L,R][L,R],用左半區間的操作更新右半區間的查詢。
在這個區間內,再對第二維(即aa維)進行排序,第二關鍵字爲第一維(即時間維)。
再對這個區間內的第二維(即aa維)進行CDQ分治,用排序後aa維前一半小的操作去跟新aa維後一半的查詢。
在第二層的CDQ中,再對第三維(即bb維)進行排序,從小到大掃描每一個操作,
對於修改操作,只有當這個操作滿足第一維在第一層CDQ的左半區間且第二維在第二層CDQ的左半區間,
纔將當前的第四維(即cc維)加入樹狀數組中。(第四維在預處理時需要離散)
對於查詢操作,只有當這個操作滿足第一維在第一層CDQ的右半區間且第二維在第二層CDQ的右半區間,
纔將當前的第四維在樹狀數組中查詢,更新答案。

代碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void MAX(T &x,T y){if(y>x)x=y;}
template<class T>inline void MIN(T &x,T y){if(y<x)x=y;}
template<class T>inline void rd(T &x){
	x=0;char o,f=1;
	while(o=getchar(),o<48)if(o==45)f=-f;
	do x=(x<<3)+(x<<1)+(o^48);
	while(o=getchar(),o>47);
	x*=f;
}
const int M=5e4+5;
const int LEFT=1;
const int RIGHT=2;
int cas,n,q,uni,OP[M],ans[M],A[M<<1],bit[M<<1];
void add(int x,int v){
	while(x<=uni){
		bit[x]+=v;
		x+=x&-x;
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=bit[x];
		x-=x&-x;
	}
	return res;
}
struct node{
	int id,x,y,z,op,part,part2;
}Q[M<<3],tmp[M<<3];
bool cmp(node &A,node &B){
	if(A.x!=B.x)return A.x<B.x;
	return A.id<B.id;
}
bool cmp2(node &A,node &B){
	if(A.y!=B.y)return A.y<B.y;
	return A.id<B.id;
}
void cdq(int l,int r){
	if(l==r)return;
	int mid=l+r>>1;
	cdq(l,mid),cdq(mid+1,r);
	for(int i=l;i<=mid;i++)Q[i].part2=LEFT;
	for(int i=mid+1;i<=r;i++)Q[i].part2=RIGHT;
	int a=l,b=mid+1,now=l;
	while(a<=mid&&b<=r){
		if(cmp2(Q[a],Q[b]))tmp[now++]=Q[a++];
		else tmp[now++]=Q[b++];
	}
	while(a<=mid)tmp[now++]=Q[a++];
	while(b<=r)tmp[now++]=Q[b++];
	for(int i=l;i<=r;i++)Q[i]=tmp[i];
	//sort(Q+l,Q+r+1,cmp2);
	for(int i=l;i<=r;i++){
		if(Q[i].op==0&&Q[i].part==LEFT&&Q[i].part2==LEFT)add(Q[i].z,1);
		if(Q[i].op!=0&&Q[i].part==RIGHT&&Q[i].part2==RIGHT)ans[Q[i].id]+=Q[i].op*query(Q[i].z);
	}
	for(int i=l;i<=r;i++)if(Q[i].op==0&&Q[i].part==LEFT&&Q[i].part2==LEFT)add(Q[i].z,-1);
}
void CDQ(int l,int r){
	if(l==r)return;
	int mid=l+r>>1;
	CDQ(l,mid),CDQ(mid+1,r);
	for(int i=l;i<=mid;i++)Q[i].part=LEFT;
	for(int i=mid+1;i<=r;i++)Q[i].part=RIGHT;
	sort(Q+l,Q+r+1,cmp);
	cdq(l,r);
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("jiedai.in","r",stdin);
	freopen("jiedai.out","w",stdout);
#endif
	rd(cas);
	while(cas--){
		n=uni=0;
		memset(ans,0,sizeof(ans));
		rd(q);
		for(int i=1;i<=q;i++){
			int x,y,z,x2,y2,z2;
			rd(OP[i]),rd(x),rd(y),rd(z);
			if(OP[i]==1){
				Q[++n]=(node){i,x,y,z,0,0,0};
				A[++uni]=z;
			}
			else{
				rd(x2),rd(y2),rd(z2);
				A[++uni]=z2;
				A[++uni]=z-1;
				Q[++n]=(node){i,x2,y2,z2,1,0,0};
				Q[++n]=(node){i,x-1,y2,z2,-1,0,0};
				Q[++n]=(node){i,x2,y-1,z2,-1,0,0};
				Q[++n]=(node){i,x2,y2,z-1,-1,0,0};
				Q[++n]=(node){i,x-1,y-1,z2,1,0,0};
				Q[++n]=(node){i,x-1,y2,z-1,1,0,0};
				Q[++n]=(node){i,x2,y-1,z-1,1,0,0};
				Q[++n]=(node){i,x-1,y-1,z-1,-1,0,0};
			}
		}
		sort(A+1,A+1+uni);
		uni=unique(A+1,A+1+uni)-A-1;
		for(int i=1;i<=n;i++)Q[i].z=lower_bound(A+1,A+1+uni,Q[i].z)-A;
		CDQ(1,n);
		for(int i=1;i<=q;i++)if(OP[i]==2)printf("%d\n",ans[i]);
	}
	return (0-0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章