HDU 3255 Farming

感谢birdstorm提供的思路以及代码


解题思路:

线段树+扫描线+离散化

首先,先将矩形以上下线的方式记录(详见代码)

再用我们先将长方体进行切割,每次只算一层的面积(总共三层),每次只更新height值大于所扫描层数的底面矩形。

hash将x1,x2离散化,并将该线段按照上下底边分类记录进线段树内。

每次在更新线段树之前,我们先计算在此前的线段树内矩形占有的面积

以高度第一层为例

(1) 0 * y1

(2)( x2 - x1 ) * ( y3 - y1 )

(3)( x4 - x1 ) * ( y2 - y3 )

(4)( x4 - x3 ) * ( y4 - y2 )

则以上为该高度的面积并,再乘以高度差(为1)

三个高度算完之后则为正确答案。


//  author birdstorm

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <vector>
#include <climits>

#define MAXN 60005
#define eps 1e-5

#define INF 0x3f3f3f3f

#define test

#define For(i,m,n) for(int i=(m);i<(n);i++)
#define vecfor(iter,a) for(vector<int>::iterator iter=a.begin();iter!=a.end();iter++)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define LL __int64


using namespace std;

struct Line
{
    int l, r, uod, y;
    int h;
} line[MAXN<<2];

struct node
{
    int l, r, mid;
    LL length, sum, cnt;
} arr[MAXN<<2];

LL num[MAXN];
int Hash[MAXN<<1];
int x[MAXN];

void build(int idx, int l, int r)
{
    arr[idx].l=l;
    arr[idx].r=r;
    arr[idx].length=Hash[r]-Hash[l];
    arr[idx].cnt=arr[idx].sum=0;
    int mid=(l+r)>>1;
    arr[idx].mid=mid;
    if(l<r)
    {
        build(idx<<1,l,mid);
        build(idx<<1|1,mid,r);
    }
}

void pushup(int idx)
{
    if(arr[idx].cnt)
        arr[idx].sum=arr[idx].length;
    else
    {
        if(arr[idx].l+1==arr[idx].r)
            arr[idx].sum=0;
        else
            arr[idx].sum=arr[idx<<1].sum+arr[idx<<1|1].sum;
    }
}

void update(int idx, int l, int r, int val)
{
    if(arr[idx].l>=l&&arr[idx].r<=r)
        arr[idx].cnt+=val;
    else
    {
        if(arr[idx].mid>l)
            update(idx<<1,l,r,val);
        if(arr[idx].mid<r)
            update(idx<<1|1,l,r,val);
    }
    pushup(idx);
}

bool cmp(Line a, Line b)
{
    return a.y<b.y;
}

int main()
{
    int t, cs=1;
    int n, m, l, r;
    int x1, x2, y1, y2, type;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        rep(i,1,m)
            scanf("%I64d",&num[i]);
        int tot=1;
        rep(i,1,n)
        {
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&type);
            int down=tot, up=tot+1;         // make it a line
            line[up].l=line[down].l=x1;     //left->right
            line[up].r=line[down].r=x2;
            line[up].h=line[down].h=num[type];
            line[down].y=y1;        // high
            line[up].y=y2;
            line[down].uod=1;       // kind
            line[up].uod=-1;
            Hash[down]=x1, Hash[up]=x2;     //there are each begin and end
            tot+=2;
        }
        sort(line+1,line+tot,cmp);
        sort(Hash+1,Hash+tot);
        sort(num+1,num+m+1);
        int cnt=unique(Hash+1,Hash+tot)-Hash;
        LL ans=0;
        rep(j,1,m)
        {
            build(1,1,cnt-1);
            LL temp=0;
            int pre=0;
            rep(i,1,tot-1)          //  discretization of the x
                if(line[i].h>=num[j])
                {
                    temp+=arr[1].sum*(line[i].y-line[pre].y);
                    int x1=lower_bound(Hash+1,Hash+cnt,line[i].l)-Hash;
                    int x2=lower_bound(Hash+1,Hash+cnt,line[i].r)-Hash;
                    update(1,x1,x2,line[i].uod);
                    pre=i;
                }
            ans+=temp*(num[j]-num[j-1]);
        }
        printf("Case %d: %I64d\n",cs++,ans);
    }
    return 0;
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值