BZOJ_2369_区间_决策单调性
BZOJ_2369_区间_决策单调性
Description
对于一个区间集合
{A1,A2……Ak}(K>1,Ai不等于Aj(i不等于J),定义其权值
S=|A1∪A2∪……AK|*|A1∩A2……∩Ak|
即它们的交区间的长度乘上它们并区间的长度。
显然,如果这些区间没有交集则权值为0。
Your Task
给定你若干互不相等的区间,选出若干区间使其权值最大。
Input
第一行n表示区间的个数
接下来n行每行两个整数l r描述一个区间[l,r]
Output
在一行中输出最大权值
Sample Input
4
1 6
4 8
2 7
3 5
1 6
4 8
2 7
3 5
Sample Output
24
HINT
样例解释
选择[1,6]和[2,7]是最优的。
数据约定
100%:1<N<=10^6,1<=L<R<=10^6
首先有结论:肯定有一种最优方案只选了两个,因为选n个不会比只选左右的区间更优。
于是按左端点排序,然后把区间包含的那种直接统计答案并踢掉。
现在左右都单调了,可以证明满足决策单调性。
直接上决策单调性即可。
注意这道题区间长度为r-l。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; __attribute__((optimize("-O3")))inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } __attribute__((optimize("-O3")))int rd() { int x=0; char s=nc(); while(s<'0'||s>'9') s=nc(); while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc(); return x; } #define N 1000050 struct Line { int l,r; bool operator < (const Line &x) const { return l<x.l; } }a[N]; struct A { int l,r,p; }Q[N]; __attribute__((optimize("-O3")))ll Y(int j,int i) { // if(a[j].r<a[i].l) return -1ll<<60; return 1ll*(a[j].r-a[i].l)*(a[i].r-a[j].l); } __attribute__((optimize("-O3")))int find(const A &a,int x) { int l=a.l,r=a.r+1; while(l<r) { int mid=(l+r)>>1; if(Y(a.p,mid)>=Y(x,mid)) l=mid+1; else r=mid; } return l; } ll ans; int n; __attribute__((optimize("-O3")))int main() { n=rd(); register int i,t=0; for(i=1;i<=n;i++) { a[i].l=rd(); a[i].r=rd(); } sort(a+1,a+n+1); a[0].r=-1; for(i=1;i<=n;i++) { if(a[i].r<=a[t].r) { ans=max(ans,1ll*(a[t].r-a[t].l)*(a[i].r-a[i].l)); }else a[++t]=a[i]; } n=t; int l=0,r=0; Q[r++]=(A){1,n,1}; for(i=2;i<=n;i++) { if(l<r) Q[l].l++; while(l<r&&Q[l].l>Q[l].r) l++; if(l<r) ans=max(ans,Y(Q[l].p,i)); if(l==r||Y(i,n)>Y(Q[r-1].p,n)) { while(l<r&&Y(i,Q[r-1].l)>Y(Q[r-1].p,Q[r-1].l)) r--; if(l==r) Q[r++]=(A){i,n,i}; else { int x=find(Q[r-1],i); Q[r-1].r=x-1; Q[r++]=(A){x,n,i}; } } } printf("%lld\n",ans); }