C.Painting the Fence
You have a long fence which consists of n sections. Unfortunately, it is not painted, so you decided to hire q painters to paint it. i-th painter will paint all sections x such that li≤x≤ri.
Unfortunately, you are on a tight budget, so you may hire only q−2 painters. Obviously, only painters you hire will do their work.
You want to maximize the number of painted sections if you choose q−2 painters optimally. A section is considered painted if at least one painter paints it.
Input
The first line contains two integers n and q (3≤n,q≤5000) — the number of sections and the number of painters availible for hire, respectively.
Then q lines follow, each describing one of the painters: i-th line contains two integers li and ri (1≤li≤ri≤n).
Output
Print one integer — maximum number of painted sections if you hire q−2 painters.
Examples
Input
7 5
1 4
4 5
5 6
6 7
3 5
Output
7
Input
4 3
1 1
2 2
3 4
Output
2
Input
4 4
1 1
2 2
2 3
3 4
Output
3
思路:
题目数据5e3可以O(n2)枚举,但是如果暴力删除和恢复就O(n3)了,肯定不行。
显然只有覆盖次数为1或者为2的地方可能因为删除而改变总覆盖数量
可以用前缀和O(1)得出删除的答案
one[i]表示1-i中被覆盖两次的次数
sec[i]表示1-i中被覆盖两次的次数
利用这样的前缀和就可以马上的出区间内被覆盖次数为1或者2的个数
先计算全选的总覆盖数量
枚举不选择的两个人,减去两个人区间并集的覆盖次数为1的个数,减去两个人区间交集的覆盖次数为2的个数,然后就得到不选这两个人的总覆盖数量,每次枚举更新答案就行了。
code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxm=5e3+5;
int cnt[maxm];//cnt[i]为i的被覆盖次数
int one[maxm];//覆盖一次的次数前缀和
int sec[maxm];//覆盖两次的次数前缀和
int l[maxm],r[maxm];
int n,q;
signed main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=q;i++){
scanf("%d%d",&l[i],&r[i]);
cnt[l[i]]++;//差分优化
cnt[r[i]+1]--;
}
int temp=0;
for(int i=1;i<=n;i++){
cnt[i]+=cnt[i-1];//前缀和恢复差分
if(cnt[i])temp++;//覆盖至少一次答案增加
one[i]=one[i-1]+(cnt[i]==1);//1-i中覆盖一次的个数
sec[i]=sec[i-1]+(cnt[i]==2);//1-i中覆盖两次的个数
}
int ans=0;
for(int i=1;i<=q;i++){
for(int j=i+1;j<=q;j++){
int t=temp;
if(r[i]<l[j]||r[j]<l[i]){//线段不相交,减去两个区间覆盖一次的个数
t-=one[r[i]]-one[l[i]-1];
t-=one[r[j]]-one[l[j]-1];
}else{//线段相交:减去并区间覆盖一次的个数,减去交区间覆盖两次的个数
t-=one[max(r[i],r[j])]-one[min(l[i],l[j])-1];
t-=sec[min(r[i],r[j])]-sec[max(l[i],l[j])-1];
}
ans=max(ans,t);
}
}
printf("%d\n",ans);
return 0;
}