空【NOIP2017提高A组模拟8.24】

题目

这里写图片描述

输入

这里写图片描述

输出

这里写图片描述

Sample Input

3
10 100
1 50
50 100

Sample Output

99

数据范围

这里写图片描述


思路

比赛时忘记包含的情况,导致样例过不了,心跳炸了。


解法

设有两条线段i,j。用l与r表示左右端点。
首先按找l排序。
分两种情况:
1.i,j是相交的。
ans=r[j]-l[i]-(r[i]-l[j])=-(r[i]+r[j])-(l[i]+l[j])。
这种情况下,是与l+r的值有关。
2.i,j是包含的。
ans=r[i]-l[i]-(r[j]-l[j])。这种情况下与r-l有关。
一个数据结构,维护r+l的最大值与r-l的最小值+一根扫描线。
时间O(n log n)。


代码

#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)

using namespace std;

const int maxn=2e5+5;
struct cy{
    int l,r,sum,del;
}a[maxn];
struct hg{
    int val,r;
}hs[maxn*2],hd[maxn*2];
int n,ans,ansmin,ansmax,nums,numd;

int read()
{
    int x=0; char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(c;c>='0'&&c<='9';c=getchar()) x=x*10+c-48;
    return x;
}
bool cmp(cy a,cy b)
{
    return a.l<b.l||a.l==b.l&&a.r>b.r;
}
void downmin(int x)
{
    while (hs[x<<1].val<hs[x].val||hs[x<<1|1].val<hs[x].val){
        if (hs[x<<1].val<hs[x<<1|1].val){
            swap(hs[x<<1].val,hs[x].val);
            swap(hs[x<<1].r,hs[x].r);
            x=x<<1;
        }
        else {
            swap(hs[x<<1|1].val,hs[x].val);
            swap(hs[x<<1|1].r,hs[x].r);
            x=x<<1|1;
        }
    }
}
void downmax(int x)
{
    while (hd[x<<1].val>hd[x].val||hd[x<<1|1].val>hd[x].val){
        if (hd[x<<1].val>hd[x<<1|1].val){
            swap(hd[x<<1].val,hd[x].val);
            swap(hd[x<<1].r,hd[x].r);
            x=x<<1;
        }
        else {
            swap(hd[x<<1|1].val,hd[x].val);
            swap(hd[x<<1|1].r,hd[x].r);
            x=x<<1|1;
        }
    }
}
void upmin(int x)
{
    while (hs[x>>1].val>hs[x].val) {
        swap(hs[x>>1].val,hs[x].val);
        swap(hs[x>>1].r,hs[x].r);
        x>>=1;
    }
}
void upmax(int x)
{
    while (hd[x>>1].val<hd[x].val) {
        swap(hd[x>>1].val,hd[x].val);
        swap(hd[x>>1].r,hd[x].r);
        x>>=1;
    }
}
int main()
{
    //freopen("T.in","r",stdin);
    n=read();
    fo(i,1,n){
        a[i].l=read(),a[i].r=read();
        a[i].sum=a[i].l+a[i].r;
        a[i].del=a[i].r-a[i].l;
    }
    sort(a+1,a+n+1,cmp);

    memset(hs,127,sizeof(hs));
    hs[0].val=0; hd[0].val=1e9+50;
    hs[0].r=1e9; hd[0].r=1e9;
    hs[++nums].val=a[1].sum,hs[nums].r=a[1].r;
    hd[++numd].val=a[1].del,hd[numd].r=a[1].r;
    int now;
    fo(i,2,n){
        now=0;
        while (hs[1].r<a[i].l){
            hs[1].val=hs[nums].val;
            hs[1].r=hs[nums].r;
            hs[nums].val=1e9; hs[nums--].r=1e9;
            downmin(1);
        }
        now=hs[1].val;
        if(now) ans=max(ans,a[i].sum-now);
        while (hd[1].r<a[i].l){
            hd[1].val=hd[numd].val;
            hd[1].r=hd[numd].r;
            hd[numd].val=0; hd[numd--].r=1e9;
            downmax(1);
        }
        now=hd[1].val;
        if (now) ans=max(now-a[i].del,ans);
        hs[++nums].val=a[i].sum; hs[nums].r=a[i].r;
        hd[++numd].val=a[i].del; hd[numd].r=a[i].r;
        upmin(nums);
        upmax(numd);
    }
    printf("%d\n",ans);
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值