hdu 3642(线段树+扫描线)

三维扫描线,枚举z寻找相交区间的立方体,然后直接扫描线求xy平面的相交三次及以上面积,乘以z区间求和就可以了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn=1e6+100;
const int maxm=2000+500;
int col[maxn<<2];
int len1[maxn<<2],len2[maxn<<2],sum[maxn<<2];//重合线段分别为1 2 3 的线段长度
int zz[maxm],xx[maxm];
typedef long long ll;
int t,n;
struct Point
{
    int x,y,z;
    void read()
    {
        scanf("%d%d%d",&x,&y,&z);
    }
};
struct graphic
{
    Point a,b;
}gg[maxm];
struct note
{
    int l,r,h;
    int z;
    int ff;
    note() {}
    note(int l,int r,int h,int ff):l(l),r(r),h(h),ff(ff) {}
    bool operator <(const note &p) const
    {
        return h<p.h;
    }
}aa[maxm];
void pushup(int l,int r,int rt)
{
    if(col[rt]>=3)
    {
        sum[rt]=xx[r+1]-xx[l];
        len1[rt]=len2[rt]=0;
    }
    else if(col[rt]==2)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1]+len1[rt<<1]+len1[rt<<1|1]+len2[rt<<1]+len2[rt<<1|1];
        len2[rt]=xx[r+1]-xx[l]-sum[rt];//总长度减去重合次数>=3的部分才是重合次数==2的部分
        len1[rt]=0;
    }
    else if(col[rt]==1)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1]+len2[rt<<1]+len2[rt<<1|1];
        len2[rt]=len1[rt<<1]+len1[rt<<1|1];
        len1[rt]=xx[r+1]-xx[l]-sum[rt]-len2[rt];//总长度减去重合次数>=和==2的部分才是重合次数==1的部分
    }
    else if(l==r)
    {
        sum[rt]=len1[rt]=len2[rt]=0;
    }
    else
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        len1[rt]=len1[rt<<1]+len1[rt<<1|1];
        len2[rt]=len2[rt<<1]+len2[rt<<1|1];
    }
}
void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]+=v;
        pushup(l,r,rt);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) update(L,R,v,l,mid,rt<<1);
    if(mid<R) update(L,R,v,mid+1,r,rt<<1|1);
    pushup(l,r,rt);
}
int main()
{
    scanf("%d",&t);
    int Case=0;
    while(t--)
    {
        scanf("%d",&n);
        int cx=0,cz=0;
         for(int i=1;i<=n;i++)
         {
             gg[i].a.read();
             gg[i].b.read();
             zz[cz++]=gg[i].a.z;
             zz[cz++]=gg[i].b.z;
             xx[cx++]=gg[i].a.x;
             xx[cx++]=gg[i].b.x;
         }
         printf("Case %d: ",++Case);
         if(n<3)
         {
             printf("0\n");
             continue;
         }
         sort(zz,zz+cz);
         sort(xx,xx+cx);
         cz=unique(zz,zz+cz)-zz;
         cx=unique(xx,xx+cx)-xx;
         int nn=2000+10;
         ll ans=0;
         for(int j=0;j<cz-1;j++)//离散化z后枚举区间,寻找各个立方体和区间重合的部分
         {
             int cnt=0;
             for(int i=1;i<=n;i++)
             {
                 if(gg[i].a.z<=zz[j]&&gg[i].b.z>zz[j])//枚举的区间是离散化z后的,所以必然小于任意一个立方体的高
                 {
                     aa[++cnt]=note(gg[i].a.x,gg[i].b.x,gg[i].a.y,1);
                     aa[++cnt]=note(gg[i].a.x,gg[i].b.x,gg[i].b.y,-1);
                 }
             }
             sort(aa+1,aa+cnt+1);
             ll sss=0;
             for(int i=1;i<=cnt;i++)
             {
                 int hl=lower_bound(xx,xx+cx,aa[i].l)-xx;
                 int hr=lower_bound(xx,xx+cx,aa[i].r)-xx;
                 sss+=(ll)sum[1]*(ll)(aa[i].h-aa[i-1].h);
                 update(hl,hr-1,aa[i].ff,0,nn,1);
             }
             ans+=sss*(ll)(zz[j+1]-zz[j]);//重合三次后的面积乘以高
         }
         printf("%lld\n",ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Wangwanxiang/p/9441834.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值