[arc076f]Exhausted?

来源:互联网 发布:文本数据挖掘 编辑:程序博客网 时间:2024/06/11 16:00

前言

你们都会hall定理推广版本。
但是我没用hall定理做啊。

题目大意

一个二分图,X部每个点i连了Y部的[1,Li]和[Ri,m]。
求n-最大匹配。

做法

考虑到二分图最大匹配等于最小覆盖。
最优方案小我们一定是选择了Y部的一个前缀和一个后缀,剩余不能因此得到覆盖的X部点要选上。
假如我们枚举选了Y部的前缀l,假设Y部选的后缀是r,那么选的点为l+mr+1+nni=1[Li<=l][Ri>=r]
把L不大于l的X部点按R加入一个桶中,那么上诉式子等于l+m+n+1max(r+sum(r))
线段树很好维护,当然也可以利用大的位置会冗余来做到线性。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=200000+10;int tree[maxn*4],ad[maxn*4],L[maxn],R[maxn],id[maxn];int i,j,k,l,r,t,n,m,ans;void build(int p,int l,int r){    if (l==r){        tree[p]=l;        return;    }    int mid=(l+r)/2;    build(p*2,l,mid);build(p*2+1,mid+1,r);    tree[p]=tree[p*2+1];}void mark(int p,int v){    tree[p]+=v;    ad[p]+=v;}void down(int p){    if (ad[p]){        mark(p*2,ad[p]);        mark(p*2+1,ad[p]);        ad[p]=0;    }}void change(int p,int l,int r,int a,int b){    if (l==a&&r==b){        mark(p,1);        return;    }    down(p);    int mid=(l+r)/2;    if (b<=mid) change(p*2,l,mid,a,b);    else if (a>mid) change(p*2+1,mid+1,r,a,b);    else{        change(p*2,l,mid,a,mid);        change(p*2+1,mid+1,r,mid+1,b);    }    tree[p]=max(tree[p*2],tree[p*2+1]);}int query(int p,int l,int r,int a,int b){    if (l==a&&r==b) return tree[p];    down(p);    int mid=(l+r)/2;    if (b<=mid) return query(p*2,l,mid,a,b);    else if (a>mid) return query(p*2+1,mid+1,r,a,b);    else return max(query(p*2,l,mid,a,mid),query(p*2+1,mid+1,r,mid+1,b));}bool cmp(int x,int y){    return L[x]<L[y];}int main(){    scanf("%d%d",&n,&m);    build(1,1,m+1);    fo(i,1,n) scanf("%d%d",&L[i],&R[i]);    fo(i,1,n) id[i]=i;    sort(id+1,id+n+1,cmp);    j=0;    ans=min(n,m);    fo(l,0,m){        while (j<n&&L[id[j+1]]==l){            j++;            change(1,1,m+1,1,R[id[j]]);        }        ans=min(ans,l+m+n+1-query(1,1,m+1,l+1,m+1));    }    printf("%d\n",n-ans);}
原创粉丝点击