HDU - 3642 | 扫描线&重复3次以上矩形面积

描述

给定n个立方体,求重复3次以上的总体积。

分析

题目中z轴数据|z|<=500,所以可以逐层判断,每层就是计算重复覆盖3次以上矩形面积

此题要注意的地方:

  1. 所给坐标为点,离散化后,则线段树上,x点维护的是坐标ls[x]到ls[x+1]间长度。
  2. 线段树维护的是当前区间覆盖次数,更新方式详间代码update。
  3. 求面积时不要用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
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值