[ARC076F]Exhausted?
Posted jefflyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC076F]Exhausted?相关的知识,希望对你有一定的参考价值。
题意:有$n$个人和$m$个椅子,椅子排成一排,坐标为$1cdots m$,每个人都想坐在一个椅子上,第$i$个人想坐的椅子的坐标要$leq Li$或$geq R_i$,椅子不够可以在任意实数位置加椅子,问最少加多少椅子
其实是问不加椅子最多坐多少个人
先考虑一个网络流做法:对每个椅子建一个点,向$T$连$1$,对每个人建一个点,$S$向它连$1$,它向对应椅子连边
这个做法可以前后缀优化建图,但还是太慢,下面我们从最小割的角度考虑这个问题
特判掉$S,T$不连通的情况,最后割掉的一定是一些$S$的出边和$T$的入边,并且这些$T$的入边构成前缀和后缀,枚举前缀$[1,l]$和后缀$[r,m]$,此时最小割为$l+m-r+1+sumlimits_{i=1}^n[L_igt l ext{ or }R_i<r]$,因为不被这两个前后缀包含的那些人必须在$S$的出边被割掉
现在要求这个式子的最小值,那么将人按$R_i$排序后扫一遍用线段树求答案即可
求最小值之前应先把答案设为$min(n,m)$,这对应着只割$S$或只割$T$的情况
#include<stdio.h> #include<algorithm> using namespace std; const int inf=2147483647; struct pr{ int l,r; }p[200010]; bool operator<(pr a,pr b){return a.r<b.r;} int mn[800010],d[800010]; void pushup(int x){ mn[x]=min(mn[x<<1],mn[x<<1|1]); } void build(int l,int r,int x){ mn[x]=l; if(l==r)return; int mid=(l+r)>>1; build(l,mid,x<<1); build(mid+1,r,x<<1|1); } void ad(int x,int v){ mn[x]+=v; d[x]+=v; } void pushdown(int x){ if(d[x]){ ad(x<<1,d[x]); ad(x<<1|1,d[x]); d[x]=0; } } void modify(int L,int R,int v,int l,int r,int x){ if(L<=l&&r<=R)return ad(x,v); int mid=(l+r)>>1; pushdown(x); if(L<=mid)modify(L,R,v,l,mid,x<<1); if(mid<R)modify(L,R,v,mid+1,r,x<<1|1); pushup(x); } int query(int L,int R,int l,int r,int x){ if(L<=l&&r<=R)return mn[x]; int mid=(l+r)>>1,res=inf; pushdown(x); if(L<=mid)res=min(res,query(L,R,l,mid,x<<1)); if(mid<R)res=min(res,query(L,R,mid+1,r,x<<1|1)); return res; } int main(){ int n,m,i,j,s; bool flag; scanf("%d%d",&n,&m); flag=1; for(i=1;i<=n;i++){ scanf("%d%d",&p[i].l,&p[i].r); if(p[i].l>0||p[i].r<m)flag=0; } if(flag){ printf("%d",n); return 0; } sort(p+1,p+n+1); build(1,m,1); for(i=1;i<=n;i++){ if(p[i].l>1)modify(1,p[i].l-1,1,1,m,1); } s=min(n,m); for(i=j=1;i<=m;i++){ while(j<=n&&p[j].r<i){ if(p[j].l>1)modify(1,p[j].l-1,-1,1,m,1); j++; } s=min(s,m-i+j+query(1,i,1,m,1)); } printf("%d",n-s); }
以上是关于[ARC076F]Exhausted?的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder ARC076F Exhausted? 霍尔定理+线段树