HDU 3642 Get The Treasury (线段树扫描线,求体积并)

时间:2022-05-17 23:02:22

参考链接 : http://blog.csdn.net/zxy_snow/article/details/6870127

题意:给你n个立方体,求覆盖三次以上(包括三次)的区域的体积

思路:先将z坐标离散后,然后一层一层地开始扫描,计算该层中覆盖>=3次的面积,这个就同二维扫描一样,然后再用面积乘以这层的高度,
    即得到该层覆盖>=3次的体积,所有层的体积加起来,即为所求。
    对于每一层,只有当该层区域在扫描的线的z1,z2范围中,才将该线条插入。
    其它操作就同POJ 1151 Atlantis 求矩形的面积并一样。

    这里要注意的是,如果扫描的时候,是用单点更新,那么就会TLE。
    后来看了网上别人的区间更新的代码,这才A了。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define lson rt<<1,L,mid
#define rson rt<<1|1,mid,R
/*
AC
参考链接
http://blog.csdn.net/zxy_snow/article/details/6870127 题意:给你n个立方体,求覆盖三次以上(包括三次)的区域的体积 思路:先将z坐标离散后,然后一层一层地开始扫描,计算该层中覆盖>=3次的面积,这个就同二维扫描一样,然后再用面积乘以这层的高度,
即得到该层覆盖>=3次的体积,所有层的体积加起来,即为所求。
对于每一层,只有当该层区域在扫描的线的z1,z2范围中,才将该线条插入。
其它操作就同POJ 1151 Atlantis 求矩形的面积并一样。 这里要注意的是,如果扫描的时候,是用单点更新,那么就会TLE。
后来看了网上别人的区间更新代码,这才A了。
*/
using namespace std;
const int maxn=;
int n;
int xval[maxn*],zval[maxn*]; //存储x和z出现的所有值
int idx,idz; //xval和zval存储的数的个数
int hashx[maxn*],hashz[maxn*]; //用于离散化
int hx,hz; //x和z离散后的个数
long long ans; struct Line{
//l r:线条的横坐标左端点和右端点;y:纵坐标值
//z1 z2:线条所处的z坐标范围
int l,r,y,z1,z2;
int tp; //标记,tp=1表示矩形的下边,tp=-1表示矩形的上边
bool operator<(const Line tmp)const{
return y<tmp.y;
}
}line[maxn*]; struct Node{
int cnt; //该区间被覆盖的次数
/*
once:该区间中被覆盖一次的线段长度
twice:该区间中被覆盖两次的线段长度
len:该区间中被覆盖>=三次的线段长度
*/
long long once,twice,len;
}tree[maxn<<]; //二分搜索x坐标对应的离散值
int binarySearchx(int m){
int l=,r=hx+,mid;
while(r-l>){
mid=(l+r)>>;
if(hashx[mid]<=m)
l=mid;
else
r=mid;
}
return l;
} void build(int rt,int L,int R){
tree[rt].cnt=tree[rt].len=tree[rt].twice=tree[rt].once=;
if(L+==R)
return;
int mid=(L+R)>>;
build(lson);
build(rson);
}
/*
还是网上看了大牛们的代码,用区间查询,才AC
原本自己就直接单点更新,导致TLE。。。
*/
void pushUp(int rt,int L,int R){
if(tree[rt].cnt>=){
tree[rt].once=tree[rt].twice=;
tree[rt].len=hashx[R]-hashx[L];
}
else if(tree[rt].cnt==){
if(L+==R){
tree[rt].once=tree[rt].len=;
tree[rt].twice=hashx[R]-hashx[L];
}
else{
tree[rt].once=;
tree[rt].len=tree[rt<<].len+tree[rt<<|].len+tree[rt<<].twice+tree[rt<<|].twice
+tree[rt<<].once+tree[rt<<|].once;
tree[rt].twice=hashx[R]-hashx[L]-tree[rt].len;
}
}
else if(tree[rt].cnt==){
if(L+==R){
tree[rt].once=hashx[R]-hashx[L];
tree[rt].twice=tree[rt].len=;
}
else{
tree[rt].len=tree[rt<<].len+tree[rt<<|].len+tree[rt<<].twice+tree[rt<<|].twice;
tree[rt].twice=tree[rt<<].once+tree[rt<<|].once;
tree[rt].once=hashx[R]-hashx[L]-tree[rt].len-tree[rt].twice;
}
}
else{
if(L+==R){
tree[rt].len=tree[rt].once=tree[rt].twice=;
}
else{
tree[rt].len=tree[rt<<].len+tree[rt<<|].len;
tree[rt].twice=tree[rt<<].twice+tree[rt<<|].twice;
tree[rt].once=tree[rt<<].once+tree[rt<<|].once;
}
}
} void update(int rt,int L,int R,int l,int r,int c){
if(l<=L&&R<=r){
tree[rt].cnt+=c;
pushUp(rt,L,R);
return;
}
int mid=(L+R)>>;
if(r<=mid)
update(lson,l,r,c);
else if(l>=mid)
update(rson,l,r,c);
else{
update(lson,l,mid,c);
update(rson,mid,r,c);
}
pushUp(rt,L,R);
}
int main()
{
int t;
int x1,y1,z1,x2,y2,z2;
scanf("%d",&t);
for(int q=;q<=t;q++){
scanf("%d",&n);
idx=idz=;
for(int i=;i<=n;i++){
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
line[*i-].l=x1;line[*i-].r=x2;line[*i-].y=y1;line[*i-].z1=z1;line[*i-].z2=z2;line[*i-].tp=;
line[*i].l=x1;line[*i].r=x2;line[*i].y=y2;line[*i].z1=z1;line[*i].z2=z2;line[*i].tp=-;
xval[++idx]=x1;
xval[++idx]=x2;
zval[++idz]=z1;
zval[++idz]=z2;
}
n=n*;
sort(line+,line+n+);
sort(xval+,xval+idx+);
sort(zval+,zval+idz+);
hx=hz=;
//将x坐标值离散化
hashx[++hx]=xval[];
for(int i=;i<=idx;i++){
if(xval[i]!=xval[i-])
hashx[++hx]=xval[i];
}
//将y坐标值离散化
hashz[++hz]=zval[];
for(int i=;i<=idz;i++){
if(zval[i]!=zval[i-])
hashz[++hz]=zval[i];
} ans=;
int minz,maxz;
int a,b;
//一层一层地扫描
for(int i=;i<hz;i++){
//minz和maxz表示该层所处的范围
minz=hashz[i];
maxz=hashz[i+];
build(,,hx);
long long s=; //该层被覆盖>=3的面积
int last=; //记录上一次扫描线的编号
for(int j=;j<=n;j++){
if(line[j].z1<=minz && maxz<=line[j].z2){
s+=tree[].len*(line[j].y-line[last].y);
last=j;
a=binarySearchx(line[j].l);
b=binarySearchx(line[j].r);
update(,,hx,a,b,line[j].tp);
}
}
ans+=s*(maxz-minz);
}
printf("Case %d: %I64d\n",q,ans);
}
return ;
}

后来这道题自己又做了一遍,基本上和之前的差不多,只不过离散化的时候就在原来数组的基础上进行

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define lson rt<<1,L,mid
#define rson rt<<1|1,mid+1,R
using namespace std;
const int maxn=+;
int n,m;
int cntx,idx;
int cntz,idz;
int hashx[maxn<<];
int hashz[maxn<<]; struct Line{
int y,l,r;
int tp;
int z1,z2;
bool operator<(const Line tmp)const{
return y<tmp.y;
}
}line[maxn<<]; struct Node{
int cnt;
int len[];
}tree[maxn<<]; void build(int rt,int L,int R){
tree[rt].cnt=;
tree[rt].len[]=tree[rt].len[]=tree[rt].len[]=;
if(L==R)
return;
int mid=(L+R)>>;
build(lson);
build(rson);
} void pushUp(int rt,int L,int R){
//别忘了考虑叶子节点的情况
if(tree[rt].cnt==){
if(L==R){
tree[rt].len[]=tree[rt].len[]=tree[rt].len[]=;
}
else{
tree[rt].len[]=tree[rt<<].len[]+tree[rt<<|].len[];
tree[rt].len[]=tree[rt<<].len[]+tree[rt<<|].len[];
tree[rt].len[]=tree[rt<<].len[]+tree[rt<<|].len[];
}
}
else if(tree[rt].cnt==){
if(L==R){
tree[rt].len[]=hashx[R+]-hashx[L];
tree[rt].len[]=tree[rt].len[]=;
}
else{
tree[rt].len[]=tree[rt<<].len[]+tree[rt<<|].len[]+tree[rt<<].len[]+tree[rt<<|].len[];
tree[rt].len[]=tree[rt<<].len[]+tree[rt<<|].len[];
tree[rt].len[]=hashx[R+]-hashx[L]-tree[rt].len[]-tree[rt].len[];
}
}
else if(tree[rt].cnt==){
if(L==R){
tree[rt].len[]=hashx[R+]-hashx[L];
tree[rt].len[]=tree[rt].len[]=;
}
else{
tree[rt].len[]=;
tree[rt].len[]=tree[rt<<].len[]+tree[rt<<].len[]+tree[rt<<].len[]
+tree[rt<<|].len[]+tree[rt<<|].len[]+tree[rt<<|].len[];
tree[rt].len[]=hashx[R+]-hashx[L]-tree[rt].len[];
}
}
else{
tree[rt].len[]=tree[rt].len[]=;
tree[rt].len[]=hashx[R+]-hashx[L];
}
}
void update(int rt,int L,int R,int l,int r,int val){
if(l<=L&&R<=r){
tree[rt].cnt+=val;
pushUp(rt,L,R);
return;
}
int mid=(L+R)>>;
if(l<=mid)
update(lson,l,r,val);
if(r>mid)
update(rson,l,r,val);
pushUp(rt,L,R);
}
int binarySearch(int x){
int l=,r=idx+,mid;
while(r-l>){
mid=(l+r)>>;
if(hashx[mid]<=x)
l=mid;
else
r=mid;
}
return l;
}
int main()
{
int t;
int x1,y1,z1,x2,y2,z2;
scanf("%d",&t);
for(int q=;q<=t;q++){
scanf("%d",&n);
cntx=cntz=;
for(int i=;i<=n;i++){
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
line[*i-].y=y1;line[*i-].l=x1;line[*i-].r=x2;
line[*i-].z1=z1;line[*i-].z2=z2;line[*i-].tp=;
line[*i].y=y2;line[*i].l=x1;line[*i].r=x2;
line[*i].z1=z1;line[*i].z2=z2;line[*i].tp=-;
hashx[cntx++]=x1;
hashx[cntx++]=x2;
hashz[cntz++]=z1;
hashz[cntz++]=z2;
}
n=n*;
sort(hashx+,hashx+cntx);
sort(hashz+,hashz+cntz);
idx=;
for(int i=;i<cntx;i++){
if(hashx[i]!=hashx[i-]){
hashx[++idx]=hashx[i];
}
}
idz=;
for(int i=;i<cntz;i++){
if(hashz[i]!=hashz[i-])
hashz[++idz]=hashz[i];
}
sort(line+,line+n+); long long ans=;
for(int i=;i<idz;i++){
long long area=;
int last=;
build(,,idx);
for(int j=;j<=n;j++){
if(line[j].z1<=hashz[i] && hashz[i+]<=line[j].z2){
//这里乘积可能会爆int,所以要转化成long long,或者将tree[1].len定义成long long
area+=(long long)tree[].len[]*(line[j].y-line[last].y);
int a=binarySearch(line[j].l);
int b=binarySearch(line[j].r)-;
update(,,idx,a,b,line[j].tp);
last=j;
}
}
ans+=area*(hashz[i+]-hashz[i]);
}
printf("Case %d: %I64d\n",q,ans);
}
return ;
}