hdu4052-Adding New Machine-题解

扫描线,受到这里的启发。

注意充分利用不相交的条件。

我的代码没用线段树,用multiset过的。

// zoj3540
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>

using namespace std;
typedef long long LL;
const int maxn = 50006;

struct node
{
    int flag;
    LL pos,st,ed;
    node(LL _pos,LL _st,LL _ed,int _flag)
    {
        pos = _pos;
        st = _st;
        ed = _ed;
        flag = _flag;
    }
    node() {}
} pp[maxn*2];
int sumpp;

int n;
LL w,h,m,Lnum,Rnum;
multiset<LL>R;
multiset<LL>L;

bool cmp(const node &p,const node &q)
{
    if(p.pos != q.pos) return p.pos < q.pos;
    return p.flag > q.flag;
}

LL call(LL st,LL ed)
{
    LL gap = ed - st - 1;
    if(gap >= m) return gap-m+1;
    else return 0;
}

LL work(LL p,LL q,LL *x1,LL *y1,LL *x2,LL *y2)
{
    LL ret = 0;
    sumpp = 0;
    R.clear();
    L.clear();
    for(int i=0; i<n; i++)
    {
        pp[sumpp++] = node(x1[i],y1[i],y2[i],1);
        pp[sumpp++] = node(x2[i],y1[i],y2[i],0);
    }
    R.insert(0);
    L.insert(q+1);

    // maybe wrong
    LL last = call(0,q+1);
    LL lastpos = 0;
    sort(pp,pp+sumpp,cmp);

    multiset<LL>::iterator it;
    for(int i=0; i<sumpp;)
    {
        if(pp[i].flag == 1)
        {
            if(pp[i].pos - lastpos)
                ret += (pp[i].pos - lastpos - 1) * last;

            do
            {
                LL st = pp[i].st;
                LL ed = pp[i].ed;
                it = R.lower_bound(-st);
                Rnum = -(*it);
                it = L.lower_bound(ed);
                Lnum = (*it);
                i++;

                last -= call(Rnum,Lnum);
                last += call(Rnum,st);
                last += call(ed,Lnum);
                R.insert(-ed);
                L.insert(st);
            }
            while(i<sumpp && pp[i].flag && pp[i].pos==pp[i-1].pos);

            ret += last;
        }
        else  // close
        {
            LL st = pp[i].st;
            LL ed = pp[i].ed;
            ret += last * (pp[i].pos - lastpos);

            it = R.upper_bound(-st);
            Rnum = -(*it);
            it = L.upper_bound(ed);
            Lnum = (*it);

            it = R.lower_bound(-ed);
            R.erase(it);
            it = L.lower_bound(st);
            L.erase(it);
            i++;

            last += call(Rnum,Lnum);
            last -= call(Rnum,st);
            last -= call(ed,Lnum);
        }
        lastpos = pp[i-1].pos;
    }
    ret += (p-lastpos) * last;
    return ret;
}

int main()
{
    while(scanf("%I64d %I64d %d %I64d",&w,&h,&n,&m) == 4)
    {
        LL u1[maxn],u2[maxn],v1[maxn],v2[maxn],p,q;

        for(int i=0; i<n; i++)
            scanf("%I64d %I64d %I64d %I64d",u1+i,v1+i,u2+i,v2+i);
        p = w;
        q = h;
        LL ans1 = work(p,q,u1,v1,u2,v2), ans2 = 0;

        if(m != 1)
        {
            p = h;
            q = w;
            ans2 = work(p,q,v1,u1,v2,u2);
        }
       // cout << ans1 << " " << ans2 << endl;
        printf("%I64d\n",ans1+ans2);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值