首先可以前缀和优化网络流建图并得到TLE的好成绩。
可以直接用霍尔定理(准确的说是其推广)转化,但是突然忘了Hull定理是啥了。
网上很多贪心都是错的,最经典的例如按照左端点排序相同就看右端点的做法可以被n=m=4, (1,3), (2,4), (2,5), (0,4)卡掉。
然后还是回来考虑网络流,开始思考这个特殊的网络流有什么转化方式可以直接做,人脑了1h后弃疗。
紧接着突然意识到最大流等于最小割!
重新看这个问题,考虑网络流的建图,令x表示左边跟n有关的点,y表示右边跟m有关的点,那么S连x流量1,y连T流量1,其余流量正无穷,表示不能割。
然后考虑最终割集长什么样,显然是左边的一些东西和右边的一个前缀和一个后缀(或者全选,这个就是m,这个特判一下即可)。
枚举右边选的前缀是[1,l],选的后缀是[r,m],(可以有l=0或者r=m+1),考虑首先这l+m-r+1条边要被割去,其次满足
Lx>l
L
x
>
l
或者
Rx<r
R
x
<
r
的(S,x,1)要被割去。
直接做是平方级别的,考虑
Lx>l
L
x
>
l
或者
Rx<r
R
x
<
r
等价于,
Lx>l
L
x
>
l
或者(
Lx≤l
L
x
≤
l
并iqe
Rx<r
R
x
<
r
),那么从小到大枚举l,就是l+m+1+(L_x>l的x的数量)可以直接维护,剩下的是在固定l的时候求最小的(L_x<=l并且R_x< r)-r,这个显然类似扫描线一下就好了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define gc getchar()
#define mp make_pair
#define fir first
#define sec second
#define N 200010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct segment{
int l,r,mn,pt;
segment *ch[2];
}*rt;pii a[N];
inline int push_up(segment* &rt) { return rt->mn=min(rt->ch[0]->mn,rt->ch[1]->mn); }
inline int update_tags(segment* &rt,int v) { return rt->mn+=v,rt->pt+=v; }
inline int push_down(segment* &rt)
{ return update_tags(rt->ch[0],rt->pt),update_tags(rt->ch[1],rt->pt),rt->pt=0; }
int build(segment* &rt,int l,int r,int x)
{
rt=new segment,rt->l=l,rt->r=r,rt->pt=0;
if(l==r) return rt->mn=x-l;int mid=(l+r)>>1;
build(rt->ch[0],l,mid,x),build(rt->ch[1],mid+1,r,x);
return push_up(rt);
}
int update(segment* &rt,int s,int t,int v)
{
if(s>t) return 0;
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return update_tags(rt,v);
if(rt->pt) push_down(rt);
if(s<=mid) update(rt->ch[0],s,t,v);
if(mid<t) update(rt->ch[1],s,t,v);
return push_up(rt);
}
int main()
{
int n=inn(),m=inn(),Ans=min(n,m);
for(int i=1,l,r;i<=n;i++)
l=inn(),r=inn(),a[i]=mp(l,r);
sort(a+1,a+n+1),build(rt,1,m+1,m+1);
for(int l=0,c=0;l<=m;l++)
{
while(c<n&&a[c+1].fir<=l)
c++,update(rt,a[c].sec+1,m+1,1);
Ans=min(Ans,n-c+l+rt->mn);
}
return !printf("%d\n",n-Ans);
}