描述
给定n个立方体,求重复3次以上的总体积。
分析
题目中z轴数据|z|<=500,所以可以逐层判断,每层就是计算重复覆盖3次以上矩形面积
此题要注意的地方:
- 所给坐标为点,离散化后,则线段树上,x点维护的是坐标ls[x]到ls[x+1]间长度。
- 线段树维护的是当前区间覆盖次数,更新方式详间代码update。
- 求面积时不要用line[i].x-line[i-1].x作为当前有效宽。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<vector>
#define cl (k<<1)
#define cr (k<<1|1)
#define Mid ((a[k].l+a[k].r)>>1)
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
#define bug printf("???\n")
typedef long long LL;
const int Inf=0x3f3f3f3f;
const double eps=1e-7;
const int maxn=2e4+50;
struct Line{
int x,y1,y2,z1,z2,t;
Line(){}
Line(int xx,int y11,int y22,int z11,int z22,int tt):x(xx),y1(y11),y2(y22),z1(z11),z2(z22),t(tt) {}
friend bool operator<(const Line&a,const Line&b){
return a.x<b.x;
// return a.t>b.t;
}
}line[maxn];
int ls[maxn],cur;
int gs(int x){return lower_bound(ls+1,ls+1+cur,x)-ls;}
struct N{
int l,r;
int ex; //ex 表示当前区域覆盖次数
int s1,s2,s3;//覆盖1、2、3次的长度
}a[maxn*4];
void build(int k,int l,int r){
a[k].l=l, a[k].r=r;
a[k].s1 = a[k].s2 = a[k].s3 = a[k].ex = 0;
if(l==r) return;
build(cl, l, Mid);
build(cr, Mid+1, r);
}
void up(int k){
//求s1
if(a[k].ex>=1){
a[k].s1 = ls[a[k].r+1] - ls[a[k].l]; //注意!
}
else{
if(a[k].l==a[k].r) a[k].s1 = 0;
else
a[k].s1 = a[cl].s1 + a[cr].s1;
}
//求s2
if(a[k].ex>=2){
a[k].s2 = ls[a[k].r+1] - ls[a[k].l];
}
else{
if(a[k].l==a[k].r) a[k].s2 = 0;
else
if(a[k].ex==1)
a[k].s2 = a[cl].s1 + a[cr].s1;
else
a[k].s2 = a[cl].s2 + a[cr].s2;
}
//求s3
if(a[k].ex>=3){
a[k].s3 = ls[a[k].r+1] - ls[a[k].l];
}
else{
if(a[k].l==a[k].r) a[k].s3 = 0;
else
if(a[k].ex==2)
a[k].s3 = a[cl].s1 + a[cr].s1;
else
if(a[k].ex==1)
a[k].s3 = a[cl].s2 + a[cr].s2;
else
a[k].s3 = a[cl].s3 + a[cr].s3;
}
}
void update(int k,int l,int r,int t){
if(l<=a[k].l&&a[k].r<=r){
a[k].ex += t;
up(k);
return;
}
if(l<=Mid) update(cl,l,r,t);
if(r> Mid) update(cr,l,r,t);
up(k);
}
int main()
{
int T,time=0;
cin>>T;
while(T--){
cur = 0;
int n;
cin>>n;
for(int i=1; i<=n; i++){
int x1,y1,z1, x2,y2,z2;
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
line[i*2] = Line(x1, y1, y2, z1, z2, 1);
line[i*2-1] = Line(x2, y1, y2, z1, z2, -1);
ls[++cur] = y1;
ls[++cur] = y2;
}
sort(ls+1, ls+1+cur);
cur = unique(ls+1, ls+1+cur)-(ls+1);
n *= 2;
sort(line+1,line+1+n);
LL ans=0;
for(int z=-500; z<=500; z++){
build(1,1,cur-1);
int lastx=0; // !必须用lastx而不能用line[i-1],因为line[i-1]不是上一条被采用的边
for(int i=1; i<=n; i++){
if(line[i].z1<=z && z<line[i].z2){
ans += (LL)a[1].s3 * (line[i].x-lastx); lastx = line[i].x;
update(1, gs(line[i].y1), gs(line[i].y2)-1, line[i].t); //注意!
}
}
}
printf("Case %d: %lld\n",++time,ans);
}
}
/*
1
4
0 0 0 4 9 10
2 3 1 7 5 2
2 3 4 3 4 5
0 0 0 4 9 10
*/