题目链接:HDU 3642 Get The Treasury
嘿嘿,早在做二维的时候我就猜到会有三维的~~~
线段树+扫描线求面积 :1.基础版 (HDU 1542) 2.升级版 (HDU 1255)
如今遇到再次升级的版本心里小小的激动了一下
从HDU 1542 单纯求面积,到HDU 1255 求覆盖次数2次及以上的面积,到HDU 3642 求覆盖次数3次及以上的体积
体积的话,因为z的范围不大,所以将z轴的每个点单独枚举,再做二维的求面积,然后乘上高度差(z[i+1]-z[i])
虽然z范围小,不过为了节约时间依旧进行了离散化,因为对每一个z坐标都要进行二维求面积
故而需要将输入保存下来每次使用,然后做二维求面积的操作就和HDU 1255 一样,不过再多加了一个覆盖次数而已
s 表示当前节点控制的x轴区被覆盖的次数
len1 表示被覆盖1次的长度
len2 表示被覆盖2次的长度
len3 表示被覆盖3次及以上的长度
后来写
q[i].len3 = q[ls].len3 + q[rs].len3;
q[i].len2 = q[ls].len2 + q[rs].len2;
q[i].len1 = q[ls].len1 + q[rs].len1;
这段代码的时候,觉得其实len1,len2,len3可以用数组len[4]来保存,类似的操作就可以用循环写
代码可以和HDU 1255 升级版对比着看
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
/*
s 表示当前节点控制的x轴区被覆盖的次数
len1 表示被覆盖1次的长度
len2 表示被覆盖2次的长度
len3 表示被覆盖3次及以上的长度
*/
const int N = 2222;
struct Edge
{
int l,r;
int h;
int f;
void init(int lx,int rx,int hx,int fx)
{
l = lx,r = rx,h = hx,f = fx;
}
}e[N<<1];
bool cmp(Edge a,Edge b)
{
return a.h < b.h;
}
struct Node
{
int l,r;
int s; //覆盖情况
int len1;
int len2;
int len3;
}q[N*8];
int x[N<<1],z[N<<1];
#define ls i<<1
#define rs i<<1|1
#define m(i) ((q[i].l + q[i].r)>>1)
void pushup(int i)
{
int r = q[i].r,l = q[i].l;
if (q[i].s >= 3)
{
q[i].len3 = x[r+1] - x[l];
q[i].len1 = q[i].len2 = 0;
}
else if (q[i].s >= 2) //其实就是等于2
{
q[i].len3 = q[ls].len3 + q[rs].len3 + q[ls].len2 + q[rs].len2 + q[ls].len1 + q[rs].len1;
q[i].len2 = x[r+1] - x[l] - q[i].len3;
q[i].len1 = 0;
}
else if (q[i].s >= 1)
{
q[i].len3 = q[ls].len3 + q[rs].len3 + q[ls].len2 + q[rs].len2;
q[i].len2 = q[ls].len1 + q[rs].len1;
q[i].len1 = x[r+1] - x[l] - q[i].len3 - q[i].len2;
}
else
{
q[i].len3 = q[ls].len3 + q[rs].len3;
q[i].len2 = q[ls].len2 + q[rs].len2;
q[i].len1 = q[ls].len1 + q[rs].len1;
}
}
void build(int i,int l,int r)
{
q[i].l = l,q[i].r = r;
if (l == r) return;
int mid = m(i);
build(ls,l,mid);
build(rs,mid+1,r);
}
void update(int i,int l,int r,int f)
{
if (l <= q[i].l&&q[i].r <= r)
{
q[i].s += f;
pushup(i);
return;
}
int mid = m(i);
if (r <= mid) update(ls,l,r,f);
else if (l > mid) update(rs,l,r,f);
else
{
update(ls,l,mid,f);
update(rs,mid+1,r,f);
}
pushup(i);
}
struct Point //需要把输入保存下来
{
int x,y,z;
void init(int xx,int yy,int zz)
{
x = xx,y = yy,z = zz;
}
}a[N<<1];
int main()
{
int T;cin>>T;int kas = 0;
while (T--)
{
int n;scanf("%d",&n);
int totx = 0,totz = 0;
int tot = 0;
int x1,y1,z1,x2,y2,z2;
for (int i = 1;i <= n;++i)
{
scanf("%d %d %d %d %d %d",&x1,&y1,&z1,&x2,&y2,&z2);
x[totx++] = x1;x[totx++] = x2;
z[totz++] = z1;z[totz++] = z2;
a[tot].init(x1,y1,z1);tot++;
a[tot].init(x2,y2,z2);tot++;
}
printf("Case %d: ",++kas);
if (n < 3)
{
puts("0");
continue;
}
sort(x,x+totx);
sort(z,z+totz);
//利用unique去重函数
totx = unique(x,x+totx) - x;
totz = unique(z,z+totz) - z;
ll ansxyz = 0;
for (int i = 0;i < totz-1;++i)//对于每一层z都做一次二维
{
int k = 0;
for (int j = 0;j < tot;j += 2)
{
if (a[j].z <= z[i]&&a[j+1].z > z[i])
{
e[k++].init(a[j].x,a[j+1].x,a[j].y,1);//上边
e[k++].init(a[j].x,a[j+1].x,a[j+1].y,-1);//下边
}
}
sort(e,e+k,cmp);
mem(q,0);
build(1,0,totx-1);
ll ansxy = 0;
for (int j = 0;j < k-1;++j)
{
int l = lower_bound(x,x+totx,e[j].l) - x;
int r = lower_bound(x,x+totx,e[j].r) - x - 1;
update(1,l,r,e[j].f);
ansxy += (ll)q[1].len3*(ll)(e[j+1].h - e[j].h);
}
ansxyz += (ll)ansxy*(ll)(z[i+1]-z[i]);
}
printf("%I64d\n",ansxyz);
}
return 0;
}
关于unique 去重函数 :
点击打开链接