HDU4052/UVA1492 Adding New Machine

博客记录了工作日的做题任务量,给出了题目链接。针对网上用线段树求矩形面积并的题解,博主因不会该方法,提出用平衡树做法,通过set维护区间,插入区间时查询前驱后继来维护答案,还提及是C++11码风的代码。

任务量统计

工作日五道题(3/5)。

题目链接

在这里插入图片描述
https://vjudge.net/problem/UVA-1492
http://acm.hdu.edu.cn/showproblem.php?pid=4052

比网上的线段树不知道快到哪里的平衡树做法

百度了这题的题解,发现都是线段树,就是先把矩形边界延长一下然后求矩形面积的并
由于我不会矩形面积求并,所以想到了下面的做法:
搞一个 s e t set set,维护这一行的区间
每次插入一个区间,就查询一下前驱后继,维护下当前答案

C++11码风的代码

#include <bits/stdc++.h>
#define maxn 50010
using namespace std;
typedef long long ll;
ll W, H, N, M;
set< pair<ll,ll> > s;
struct machine
{
    ll left, right, up, down;
}mch[maxn];
struct event
{
    ll l, r, type, id;
}evt[maxn<<1];
bool operator<(event e1, event e2)
{
    if(e1.id==e2.id)return e1.type<e2.type;
    return e1.id < e2.id;
}
ll read(ll x=0)
{
    ll c, f=1;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-48;
    return f*x;
}
ll f(ll x){return max(0ll,x-M+1);}
int main()
{
    ll i, j, tot, ans, now;
    while(~scanf("%lld%lld%lld%lld",&W,&H,&N,&M))
    {
        if(N==0)
        {
            ans=f(W)*H + f(H)*W;
            if(M==1)ans/=2;
            printf("%lld\n",ans);
            continue;
        }

        ans=0;
        for(i=1;i<=N;i++)
        {
            mch[i].left=read();
            mch[i].up=read();
            mch[i].right=read();
            mch[i].down=read();
        }

        tot=0;
        for(i=1;i<=N;i++)
        {
            evt[++tot]=(event){mch[i].left,mch[i].right,+1,mch[i].up};
            evt[++tot]=(event){mch[i].left,mch[i].right,-1,mch[i].down+1};
        }
        sort(evt+1,evt+tot+1);
        s.clear();
        s.emplace(make_pair(0,0));
        s.emplace(make_pair(W+1,W+1));
        now=f(W);
        for(i=1;i<=tot;i++)
        {
            if(i==1)ans+=f(W)*(evt[i].id-1);
            else ans+=(evt[i].id-evt[i-1].id)*now;
            if(i==tot)ans+=f(W)*(H-evt[i].id+1);
            if(evt[i].type==+1)
            {
                auto I=make_pair(evt[i].l,evt[i].r);
                s.emplace(I);
                auto pre=s.find(I), suf=s.find(I);
                pre--, suf++;
                now -= f(suf->first - pre->second - 1);
                now += f(I.first - pre->second - 1);
                now += f(suf->first - I.second - 1);
            }
            else
            {
                auto I=make_pair(evt[i].l,evt[i].r);
                auto pre=s.find(I), suf=s.find(I);
                pre--, suf++;
                now -= f(I.first - pre->second - 1);
                now -= f(suf->first - I.second - 1);
                now += f(suf->first - pre->second - 1);
                s.erase(I);
            }
        }

        tot=0;
        for(i=1;i<=N;i++)
        {
            evt[++tot]=(event){mch[i].up,mch[i].down,+1,mch[i].left};
            evt[++tot]=(event){mch[i].up,mch[i].down,-1,mch[i].right+1};
        }
        sort(evt+1,evt+tot+1);
        s.clear();
        s.emplace(make_pair(0,0));
        s.emplace(make_pair(H+1,H+1));
        now=f(H);
        for(i=1;i<=tot;i++)
        {
            if(i==1)ans+=f(H)*(evt[i].id-1);
            else ans+=(evt[i].id-evt[i-1].id)*now;
            if(i==tot)ans+=f(H)*(W-evt[i].id+1);
            if(evt[i].type==+1)
            {
                auto I=make_pair(evt[i].l,evt[i].r);
                s.emplace(I);
                auto pre=s.find(I), suf=s.find(I);
                pre--, suf++;
                now -= f(suf->first - pre->second - 1);
                now += f(I.first - pre->second - 1);
                now += f(suf->first - I.second - 1);
            }
            else
            {
                auto I=make_pair(evt[i].l,evt[i].r);
                auto pre=s.find(I), suf=s.find(I);
                pre--, suf++;
                now -= f(I.first - pre->second - 1);
                now -= f(suf->first - I.second - 1);
                now += f(suf->first - pre->second - 1);
                s.erase(I);
            }
        }

        if(M==1)ans/=2;
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值