hdu 3642:Get The Treasury

文章介绍了一个编程问题,通过将三维坐标离散化并转化为二维问题,利用扫描线算法和线段树来解决长方体重叠体积超过3次的计算。具体方法包括对每个高度切面进行扫描,计算覆盖三次的面积,并乘以高度差得到体积。代码示例展示了如何实现这一算法。
摘要由CSDN通过智能技术生成

题目链接如下所示:

http://acm.hdu.edu.cn/showproblem.php?pid=3642

大意是说,给一堆的长方体,如果重叠体积的次数达到了3次及以上,那么就说明这个地方是有宝藏的,任务就是计算有宝藏的体积,其实就是算重叠3次及以上的体积多少。

这个是用扫描线加上线段树来做,不过我们首先要把三维转化成二维的问题,首先将三维的坐标离散化,这样,然后对单个高度的切面进行扫描线处理,这里就转化成二维了,算出这个平面覆盖三次的面积,乘以离散化的高度差(这里用下一个离散值减去当前离散值,因为下一个离散值一定是最接近的保证覆盖次数是3的那个高度)就是体积

代码如下所示:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<cmath>
#include<climits>

using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r

typedef long long ll;
const int MAXN=1e5+7;
int sum1[MAXN], sum2[MAXN], sum3[MAXN];
int cover[MAXN];
int x[MAXN], z[MAXN];
int n;

struct Node{
    int l,r,h,f;
}line[MAXN];

struct point{
    int x,y,z;
};

struct node{
    point a,b;
}cube[MAXN];

void init(){
    memset(sum1, 0, sizeof(sum1));
    memset(sum2, 0, sizeof(sum2));
    memset(sum3, 0, sizeof(sum3));
    memset(cover, 0, sizeof(cover));
}

bool cmp(Node a, Node b){
    return a.h<b.h;
}

void push_up(int rt,int l,int r){
    if (cover[rt] > 2){
        sum3[rt]=x[r+1]-x[l];
        sum1[rt]=sum2[rt]=0;
    } else if (cover[rt] == 2){
        if (l==r){
            sum1[rt]=sum3[rt]=0;
            sum2[rt]=x[r+1]-x[l];
        } else{
            sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1]+sum2[rt<<1]+sum2[rt<<1|1]+sum1[rt<<1]+sum1[rt<<1|1];
            sum2[rt]=x[r+1]-x[l]-sum3[rt];
            sum1[rt]=0;
        }
    } else if (cover[rt] == 1){
        if (l==r){
            sum2[rt]=sum3[rt]=0;
            sum1[rt]=x[r+1]-x[l];
        } else{
            sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1]+sum2[rt<<1]+sum2[rt<<1|1];
            sum2[rt]=sum1[rt<<1]+sum1[rt<<1|1];
            sum1[rt]=x[r+1]-x[l]-sum3[rt]-sum2[rt];
        }
    } else {
        if (l==r){
            sum1[rt]=sum2[rt]=sum3[rt]=0;
        } else{
            sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1];
            sum2[rt]=sum2[rt<<1]+sum2[rt<<1|1];
            sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];
        }
    }
}

void update(int rt, int l, int r, int ul, int ur, int val){
    if (ul<=l && r<=ur){
        cover[rt]+=val;
        push_up(rt,l,r);
        return;
    }
    int mid = (l+r)>>1;
    if (ul<=mid){
        update(lson,ul,ur,val);
    }
    if (mid<ur){
        update(rson,ul,ur,val);
    }
    push_up(rt,l,r);
}


int main(){
    int t,cas=0;
    scanf("%d", &t);
    while (t--){
        ll ans=0;
        int cntx=0,cntz=0;
        scanf("%d",&n);
        for (int i = 1; i <= n; ++i) {
            scanf("%d %d %d %d %d %d",&cube[i].a.x,&cube[i].a.y,&cube[i].a.z,&cube[i].b.x,&cube[i].b.y,&cube[i].b.z);
            x[++cntx]=cube[i].a.x;
            x[++cntx]=cube[i].b.x;
            z[++cntz]=cube[i].a.z;
            z[++cntz]=cube[i].b.z;
        }
        if (n<3) {
            printf("Case %d: 0\n",++cas);
            continue;
        }
        sort(x+1,x+1+cntx);
        sort(z+1,z+1+cntz);
        cntx= unique(x+1,x+1+cntx)-x-1;
        cntz= unique(z+1,z+1+cntz)-z-1;
        for (int i = 1; i < cntz; ++i) {
            int tot=0;
            for (int k = 1; k <= n; ++k) {
                if (cube[k].a.z<=z[i] && z[i]<cube[k].b.z){
                    int x1=cube[k].a.x, x2=cube[k].b.x;
                    int y1=cube[k].a.y, y2=cube[k].b.y;
                    line[++tot].l=x1,line[tot].r=x2,line[tot].h=y1,line[tot].f=1;
                    line[++tot].l=x1,line[tot].r=x2,line[tot].h=y2,line[tot].f=-1;
                }
            }
            init();
            sort(line+1,line+1+tot,cmp);
            ll res=0;
            for (int k = 1; k < tot; ++k) {
                int l = lower_bound(x+1,x+1+cntx,line[k].l)-x;
                int r = lower_bound(x+1,x+1+cntx,line[k].r)-x-1;
                update(1,1,cntx,l,r,line[k].f);
                res+=(ll)sum3[1]*(line[k+1].h-line[k].h);
            }
            ans+=res*(z[i+1]-z[i]);
        }
        printf("Case %d: %lld\n",++cas, ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值