Get The Treasury(HDU--3642) 线段树+扫描线问题

这道题唯一的一个难点应该就是如何去处理三维情况下的扫描线
这里其实我们可以这样想:先以Z轴为扫描线,然后我们单独考虑在此情况下的那个平面的样子,然后我们就可以将这个问题处理成了二维的面积相交问题。
但其实还是挺不好写的(主要还是我太菜了)
我们可以慢慢的理一下思路
首先我们可以想到这个线段树的pushdown操作其实是不需要的,因为每次查询的时候我们只需要知道根节点(整棵树)的情况即可,所以pushdown可以不用写了。
然后我们可以考虑一下题中给的数据范围,x和y的范围均为[-1e6,1e6],但是我们可以发现这个n的范围只有1e3所以我们可以考虑将这些点离散化一下。
处理好思路应该就好写很多了,不过写的时候要注意一些细节问题

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<time.h>
#include<queue>
#include<unordered_map>
#include<stack>
#include<map>
#include<set>
#include<vector>
#define endl "\n"
#define x first
#define y second
#define Endl endl
#define int long long
typedef long long ll;
const int INF=0x7fffffff;
const double PI=3.14159265359;
using namespace std;
const int N=3e6+10; 
vector<int>xx,yy,zz;//分别对x,y,z进行离散化 
int idx;
struct point{
	int l,r;
	int cnt;
	int sum1,sum2,sum3;//sumx记录被覆盖大于等于x次的长度 
}tr[N*4];
struct edge{
	int x1,x2,y1,y2,z1,z2;
}a[N]; 
struct pp{
	int x1,x2;
	int y;
	int z1,z2;
	int type;
	bool operator <(const pp&a){
		return y<a.y;
	}
}s[N];
struct pppp{
	int x1,x2;
	int y;
	int type;
}b[N];
int find(int x,int type){//find函数查找离散化之前的值  
	if(type==1) return xx[x];
	else if(type==2) return yy[x];
	else return zz[x];
}
void pushup(int root){//分别维护好sum1,sum2,sum3的值 
	int ch=root<<1;
	if(tr[root].cnt>=3){
		tr[root].sum3=find(tr[root].r+1,1)-find(tr[root].l,1);//这里对r加一的目的是因为我们已经把线段映射到数组中了,那么我们恢复的时候自然要进行+1的操作 
		tr[root].sum1=tr[root].sum2=tr[root].sum3;
	}
	else if(tr[root].cnt>=2){//该线段已经被覆盖两次了,所以该段中sum3的值应该该是两个儿子的sum1的值之和(这样可以省去pushdown的操作) 
		if(tr[root].l!=tr[root].r)
			tr[root].sum3=tr[ch].sum1+tr[ch+1].sum1;
		else tr[root].sum3=0;
		tr[root].sum2=find(tr[root].r+1,1)-find(tr[root].l,1);
		tr[root].sum1=tr[root].sum2;
	}
	else if(tr[root].cnt>=1){
		if(tr[root].l!=tr[root].r){
			tr[root].sum3=tr[ch].sum2+tr[ch+1].sum2;
			tr[root].sum2=tr[ch].sum1+tr[ch+1].sum1;	
		}
		else{
			tr[root].sum3=tr[root].sum2=0;
		} 
		tr[root].sum1=find(tr[root].r+1,1)-find(tr[root].l,1);
	}
	else{
	if(tr[root].l!=tr[root].r){
			tr[root].sum3=tr[ch].sum3+tr[ch+1].sum3;
			tr[root].sum2=tr[ch].sum2+tr[ch+1].sum2;	
			tr[root].sum1=tr[ch].sum1+tr[ch+1].sum1;
		}
		else{
			tr[root].sum3=tr[root].sum3=tr[root].sum1=0;
		} 
	}
}
void build(int root,int l,int r){
	tr[root].l=l;
	tr[root].r=r;
	tr[root].cnt=0;
	tr[root].sum1=0;
	tr[root].sum2=0;
	tr[root].sum3=0;
	if(l!=r){
		int mid=(l+r)>>1;
		int ch=root<<1;
		build(ch,l,mid);
		build(ch+1,mid+1,r);
	}
}
void change(int root,int l,int r,int x){
	if(tr[root].l==l&&tr[root].r==r){
		tr[root].cnt+=x;
		pushup(root);
		return ;
	}	
	int mid=(tr[root].l+tr[root].r)>>1;
	int ch=root<<1;
	if(r<=mid) change(ch,l,r,x);
	else if(l>mid) change(ch+1,l,r,x);
	else change(ch,l,mid,x),change(ch+1,mid+1,r,x);
	pushup(root);
}
void solve(){
	int cnt=0;
	int ans=0;
	xx.clear();
	yy.clear();
	zz.clear();
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].x1>>a[i].y1>>a[i].z1>>a[i].x2>>a[i].y2>>a[i].z2;
		xx.push_back(a[i].x1),xx.push_back(a[i].x2);
		yy.push_back(a[i].y1),yy.push_back(a[i].y2);
		zz.push_back(a[i].z1),zz.push_back(a[i].z2);
	}
	sort(xx.begin(),xx.end());
	sort(yy.begin(),yy.end());
	sort(zz.begin(),zz.end());
	xx.erase(unique(xx.begin(),xx.end()),xx.end());
	yy.erase(unique(yy.begin(),yy.end()),yy.end());
	zz.erase(unique(zz.begin(),zz.end()),zz.end());
	for(int i=1;i<=n;i++){
		a[i].x1=lower_bound(xx.begin(),xx.end(),a[i].x1)-xx.begin();
		a[i].x2=lower_bound(xx.begin(),xx.end(),a[i].x2)-xx.begin();
		a[i].y1=lower_bound(yy.begin(),yy.end(),a[i].y1)-yy.begin();
		a[i].y2=lower_bound(yy.begin(),yy.end(),a[i].y2)-yy.begin();
		a[i].z1=lower_bound(zz.begin(),zz.end(),a[i].z1)-zz.begin();
		a[i].z2=lower_bound(zz.begin(),zz.end(),a[i].z2)-zz.begin();
		s[++cnt]={a[i].x1,a[i].x2,a[i].y1,a[i].z1,a[i].z2,1};
		s[++cnt]={a[i].x1,a[i].x2,a[i].y2,a[i].z1,a[i].z2,-1};
	}
	sort(s+1,s+1+cnt);//按照y的大小排序 
	for(int i=0;i<zz.size()-1;i++){
		build(1,0,xx.size());
		int last=-1;
		int tot=0;
		int temp=find(i+1,3)-find(i,3);
		for(int j=1;j<=cnt;j++){
			if(s[j].z1<=i&&s[j].z2>i){
				b[++tot]={s[j].x1,s[j].x2,s[j].y,s[j].type};//b记录满足要求的矩形 
			}
		}
		for(int j=1;j<=tot;j++){
			int k1=b[j].x1,k2=b[j].x2-1;//这里减1的目的是将线段映射为数组 
			if(j!=1)
			ans+=temp*(find(b[j].y,2)-find(b[j-1].y,2))*tr[1].sum3;
			change(1,k1,k2,b[j].type);

		}
	}
	cout<<"Case "<<++idx<<": "<<ans<<endl;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T;
	cin>>T;
	while(T--){
		solve();
	}

}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值