BZOJ2687: 交与并

$n \leq 1e6$个区间,定义一个区间集合的权值为:并集大小-交集大小。求一个权值最大的大小至少为2的集合。

好题。

在一个区间集合中,可以发现除了左右端点涉及的区间外,里面剩余的区间越少,并集不会变但交集会越大,因此答案会更优。但我们需要集合大小至少为2,因此变成选两个区间。

左右端点可能涉及一个或两个区间。前者要求选中两个包含关系的集合,后者则不包含。

包含:

按右端点排序后,对每个$i$,求$L_j \geq L_i$的最大区间,$j<i$。

其实不必这样。当两个区间成包含关系时,小区间和其他区间不可能比大区间和其他间更优(画画图分分类),因此小区间贡献完一次就直接删掉。可以用个栈。

不包含:

前面说被包含的区间在这没贡献了,删之,得到一个$R$递增$L$递增的区间序列。排序之。

然后可以证明决策单调性。我:???

好这么证。无非就是要证:$p<q<i$时决策$i$,$p$比$q$优,那么在决策$i-1$时$p$不可能不如$q$。

反证之。由$p$比$q$优得到$(R_i-L_p)(R_p-L_i)>(R_i-L_q)(R_q-L_i)$,整理得$R_i(R_p-R_q)+L_i(L_p-L_q)-L_pR_p+L_qR_q>0$。在$i-1$处由$q$比$p$优同理可以得到$R_{i-1}(R_q-R_p)+L_{i-1}(L_q-L_p)+L_pR_p-L_qR_q>0$,两式相减得$(R_i-R_{i-1})(R_p-R_q)+(L_i-L_{i-1})(L_p-L_q)>0$,但这是不可能的,得证。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 //#include<set>
 5 #include<algorithm>
 6 //#include<math.h>
 7 //#include<iostream>
 8 //#include<time.h>
 9 using namespace std;
10  
11 #define LL long long
12 int qread()
13 {
14     char c; int s=0,t=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (t=-1);
15     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*t;
16 }
17  
18 //Pay attention to read!
19  
20 int n;
21 #define maxn 1000011
22 struct QQ{int l,r,v;}qq[maxn];
23 bool vis[maxn];
24 bool cmpr(const QQ &a,const QQ &b) {return a.r<b.r;}
25 LL ans;
26 void solve(int L,int R,int ql,int qr)
27 {
28     if (L>R || ql>qr) return;
29     int mid=(ql+qr)>>1;
30     int id=mid; LL tmp=0,v;
31     for (int i=L,to=min(mid-1,R);i<=to;i++)
32         if ((v=(qq[mid].r-qq[i].l)*1ll*(qq[i].r-qq[mid].l))>tmp) {tmp=v; id=i;}
33     ans=max(ans,tmp);
34     solve(L,id,ql,mid-1); solve(id,R,mid+1,qr);
35 }
36  
37 int sta[maxn],top=0;
38 int main()
39 {
40     n=qread();
41     for (int i=1;i<=n;i++) {qq[i].l=qread(); qq[i].r=qread(); qq[i].v=qq[i].r-qq[i].l;}
42     sort(qq+1,qq+1+n,cmpr);
43      
44     ans=0;
45     sta[++top]=1;
46     for (int i=2;i<=n;i++)
47     {
48         int last=0;
49         while (top && qq[sta[top]].l>=qq[i].l)
50             last=sta[top],vis[last]=1,ans=max(ans,qq[i].v*1ll*qq[last].v),top--;
51         sta[++top]=i;
52     }
53      
54     int nn=0;
55     for (int i=1;i<=n;i++) if (!vis[i]) qq[++nn]=qq[i]; n=nn;
56     solve(1,n,1,n);
57      
58     printf("%lld\n",ans);
59     return 0;
60 }
View Code

 

posted @ 2018-05-23 14:09  Blue233333  阅读(331)  评论(0编辑  收藏  举报