bzoj2687: 交与并
Description
对于一个区间集合{A1,A2……AK}(K>1,Ai<>Aj{i<>j}),我们定义其权值
W=|A1∪A2∪……∪AK|*|A1∩A2∩……AK|
当然,如果这些区间没有交集则权值为0。
Input
给你N个各不相同的区间,请你从中找出若干个区间使其权值最大。
第一行N
接下来N行 l r(1<=l<r<=10^6)
Output
最大权值
Sample Input
4
1 6
4 8
2 7
3 5
1 6
4 8
2 7
3 5
Sample Output
24
样例注释:选择第1个和第3个区间,交为(2,6),并为(1,7),
权值为4*6=24.
样例注释:选择第1个和第3个区间,交为(2,6),并为(1,7),
权值为4*6=24.
HINT
100% 1<N<=10^6
题解:
选出的最优区间集合满足下列性质:
1.交集肯定不能为空。
2.设这个区间集合的并集为U,对于任意一个区间,设这个区间集合去掉这个区间的并集为U',满足U'⫋U。
第一条显然。。。
第二条:假如去掉这个集合后并集没有减小,去掉后显然交集不会减小,所以答案也不会变小。
所以选出来的集合只有一个区间或两个互不包含的区间。
由于集合大小不能为1,所以只能选两个区间。
首先我们将区间按左端点从小到大,如果左端点相同,则按右端点从大到小的顺序排好序。
对于其中一个区间含于另一个区间的情况:显然包含它的区间只能在他前面,而且具有单调性,所以用个单调队列维护一下即可。
对于两个互不包含的区间的情况:先将含于其他区间的区间去掉,这时区间的左右端点都单调上升,然后有一个性质:
假如第i-1个区间选择的最优区间为第k个(k<i-1),第i个区间选择的最优区间为第j个(j<i),则有k<=j
证明:
假设j<k,对于i,有:
同理,对于i-1(记作i'),有:
所以假设不成立,所以有k<=j,这样就有决策单调性了,用栈来维护一下即可。
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 char ch; 8 bool ok; 9 void read(int &x){ 10 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 11 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 12 if (ok) x=-x; 13 } 14 const int maxn=1000005; 15 typedef long long int64; 16 int n,cnt,last; 17 int64 ans; 18 struct Seg{ 19 int l,r; 20 }seg[maxn]; 21 inline bool cmp(const Seg &a,const Seg &b){return (a.l<b.l)||(a.l==b.l&&a.r>b.r);} 22 inline int64 calc(const Seg &j,const Seg &i){return 1LL*(i.r-j.l)*(j.r-i.l);} 23 struct Stack{ 24 int top,pos; 25 struct Data{ 26 int l,r,id; 27 }s[maxn],tmp; 28 void init(){s[top=1]=(Data){2,n,1},pos=1;} 29 bool cmp(int a,int x,int y){return calc(seg[x],seg[a])<calc(seg[y],seg[a]);} 30 int get(int id){ 31 int l=tmp.l,r=tmp.r,m,a=tmp.id; 32 while (l<r){ 33 m=((l+r)>>1)+1; 34 if (cmp(m,a,id)) l=m; else r=m-1; 35 } 36 return l; 37 } 38 void push(int id){ 39 while (top&&!cmp(s[top].l,s[top].id,id)) top--; 40 tmp=s[top--]; 41 int m=get(id); 42 if (tmp.l<=m) s[++top]=(Data){tmp.l,m,tmp.id}; 43 if (m<n) s[++top]=(Data){m+1,n,id}; 44 } 45 int64 query(int x){ 46 while (x>s[pos].r) pos++; 47 return calc(seg[s[pos].id],seg[x]); 48 } 49 }stack; 50 struct Que{ 51 int head,tail; 52 struct Data{ 53 int r,len; 54 }q[maxn],tmp; 55 void init(){head=1,tail=0;} 56 void push(int id){ 57 tmp=(Data){seg[id].r,seg[id].r-seg[id].l}; 58 while (head<=tail&&q[tail].len<=tmp.len) tail--; 59 q[++tail]=tmp; 60 } 61 int64 query(int id){ 62 int r=seg[id].r; 63 while (head<=tail&&q[head].r<r) head++; 64 if (head<=tail) return q[head].len; 65 else return -1; 66 } 67 }que; 68 int main(){ 69 read(n); 70 for (int i=1;i<=n;i++) read(seg[i].l),read(seg[i].r); 71 sort(seg+1,seg+n+1,cmp),que.init(); 72 for (int i=1;i<=n;i++) 73 if (seg[i].r>last) last=seg[i].r,seg[++cnt]=seg[i],que.push(i); 74 else ans=max(ans,que.query(i)*(seg[i].r-seg[i].l)); 75 n=cnt,stack.init(); 76 for (int i=2;i<=n;i++) ans=max(ans,stack.query(i)),stack.push(i); 77 printf("%lld\n",ans); 78 return 0; 79 }