bzoj4951 [Wf2017]Money for Nothing
题解:
答案显然是$max((q-p)*(e-d))$
依然先贪心。
对于工厂,我们倾向于$pi<pj,di<dj$的;
对于买家,我们倾向于$qi>qj,ei>ej$的。
于是将一定不是最优解的工厂和买家划掉。
然后我们发现这个东西是满足决策单调性的。
问我怎么证?画一个二维坐标系,然后将选中的点都画上,然后就理性易证了。
最后分治。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 500050 #define ll long long inline ll rd() { ll f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n0,m0,n,m; struct Pair { ll x,y; Pair(){} Pair(ll x,ll y):x(x),y(y){} }; bool cmp1(Pair a,Pair b) { if(a.x!=b.x)return a.x<b.x; return a.y<b.y; } bool cmp2(Pair a,Pair b) { if(a.x!=b.x)return a.x<b.x; return a.y>b.y; } Pair a0[N],b0[N],a[N],b[N]; ll ans = 0; void divi(int l1,int r1,int l2,int r2) { if(l1>r1||l2>r2)return ; if(l1==r1) { for(int i=l2;i<=r2;i++) if(b[i].x>a[l1].x)ans = max(ans,(b[i].x-a[l1].x)*(b[i].y-a[l1].y)); return ; } if(l2==r2) { for(int i=l1;i<=r1;i++) if(b[l2].x>a[i].x)ans = max(ans,(b[l2].x-a[i].x)*(b[l2].y-a[i].y)); return ; } int mid = (l2+r2)>>1; int pos=l1; ll max_val=-0x3f3f3f3f3f3f3f3fll; for(int i=l1;i<=r1;i++) { if(b[mid].x<=a[i].x&&b[mid].y<=a[i].y)continue; if((b[mid].x-a[i].x)*(b[mid].y-a[i].y)>max_val) { pos = i; max_val=(b[mid].x-a[i].x)*(b[mid].y-a[i].y); } } ans=max(ans,max_val); divi(l1,pos,l2,mid-1); divi(pos,r1,mid+1,r2); } int main() { // freopen("33.in","r",stdin); n0 = rd(),m0 = rd(); for(int i=1;i<=n0;i++) a0[i].x = rd(),a0[i].y = rd(); for(int i=1;i<=m0;i++) b0[i].x = rd(),b0[i].y = rd(); sort(a0+1,a0+1+n0,cmp1); sort(b0+1,b0+1+m0,cmp2); ll lim = 0x3f3f3f3f3f3f3f3fll; for(int i=1;i<=n0;i++) if(a0[i].y<lim) { a[++n]=a0[i]; lim = a0[i].y; } for(int i=1;i<=m0;i++) { while(m&&b[m].y<=b0[i].y)m--; b[++m]=b0[i]; } divi(1,n,1,m); printf("%lld\n",ans); return 0; }