BZOJ4951 [Wf 2017] 分治 解题报告

4951: [Wf2017]Money for Nothing

Description

在这道题种你需要解决一个全世界人类从存在起就在面临的最深刻的问题–如何发大财。你是一名零件交易市场的中介。你的工作是从零件生产公司那里买到零件,然后把它们卖给零件消费公司。每个零件消费公司在截止日期前每天都会对一个零件有一个开放式的需求,以及它愿意买下零件的价格。另一方面,每个零件生产公司在开始日期及以后都可以销售零件,以及它销售零件的价格。基于公平竞争法,你只能与一家生产公司、一家消费公司签订合同。你可以在生产公司开始销售后每天从生产公司买一个零件,当然这也要在消费公司结束需求之前。在这些天里,每天你可以从买卖差价中获取利润。你的任务是选择能使你利益最大化的生产公司与消费公司。

Input

第一行包含两个整数m和n(1≤m,n≤500 000),分别表示市场里生产公司与消费公司的数量。
接下来m行,第i行包含两个整数pi和di(1≤pi,di≤10^9),表示第i个生产者卖一个零件的价格和第一个零件开始卖的日期。
接下来n行,第j行包含两个整数qj和ej(1≤qj,ej≤ 10^9)
表示第j个消费者愿意买一个零件的价格和它可以接收最后一个零件的日期的下一天。

Output

输出你最多能赚到多少钱。如果你没办法通过签合同获利,输出0。

Sample Input

样例1

2 2
1 3
2 1
3 5
7 2

样例2

1 2
10 10
9 11
11 9

Sample Output

样例1

5

样例2

0

【解题报告】

把重要的话说在前面:千万不要 #define max(a,b) (a < b) ? b:a!!!
我已开始因为这个狂TLE不止。。。
因为只让你选一个买进点和一个卖出点,所以我们把所有点花在坐标上,
可以发现这道题求的是最大矩形面积。
排除掉冗余的点之后(init()),考虑分治,u[i]表示与i匹配的最优点
每次我们处理左下角在l1∼r1之间,右上角在l2∼r2之间的最大值,设
递归下去找 1∼md,l2∼u(md)和md∼r1,u(md)∼r2。

代码如下:

/**************************************************************
    Problem: 4951
    User: onepointo
    Language: C++
    Result: Accepted
    Time:27048 ms
    Memory:9124 kb
****************************************************************/

#include
#include
#include
using namespace std;
#define LL long long
#define N 500010

int n,m;
struct Data
{
    int x,y;
    bool friend operator < (Data a,Data b)
    {return a.x==b.x?a.ybool ban[N];

void init(Data *a,int &size,int type)
{
    sort(a+1,a+size+1);
    memset(ban,0,sizeof(ban));
    if(!type)
    {
        int pre=1;
        for(int i=2;i<=size;++i)
        {
            if(a[i].y>=a[pre].y) ban[i]=1;
            else pre=i;
        }
    }
    if(type)
    {
        int pre=size;
        for(int i=size-1;i;--i)
        {
            if(a[i].y<=a[pre].y) ban[i]=1;
            else pre=i;
        }
    }
    int cnt=0;
    for(int i=1;i<=size;++i)
    if(!ban[i]) a[++cnt]=a[i];
    size=cnt;
}
LL cal(int x,int y)
{
    if(b[y].xreturn 0;
    return 1LL*(b[y].x-a[x].x)*(b[y].y-a[x].y);
}
LL solve(int l1,int r1,int l2,int r2)
{ 
    if(l1==r1) return 0;
    int mid1=(l1+r1)>>1,mid2=l2;
    for(int i=l2+1;iif(cal(mid1,mid2)return max(max(solve(l1,mid1,l2,mid2+1),solve(mid1+1,r1,mid2,r2)),cal(mid1,mid2));
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%d%d",&a[i].x,&a[i].y);
    for(int i=1;i<=m;++i) scanf("%d%d",&b[i].x,&b[i].y);
    init(a,n,0);
    init(b,m,1);
    printf("%lld\n",solve(1,n+1,1,m+1));
    return 0;
}

你可能感兴趣的:(————二分三分————)