S向每头奶牛连边,容量1
每个防晒霜向T连边,容量cover
每头奶牛向SPF在自己范围内的防晒霜连边,容量inf
用线段树优化建图跑最大流即可。
#include<cstdio> const int N=7010,inf=~0U>>2; struct edge{int t,f;edge*nxt,*pair;}*g[N],*d[N],pool[60000],*cur=pool,*p; int n,m,tot,root,id[N],l[N],r[N],spf[N][2],i,x,y,S,T,h[N],gap[N],maxflow; inline int min(int x,int y){return x<y?x:y;} inline void add(int s,int t,int f){ p=cur++;p->t=t;p->f=f;p->nxt=g[s];g[s]=p; p=cur++;p->t=s;p->f=0;p->nxt=g[t];g[t]=p; g[s]->pair=g[t];g[t]->pair=g[s]; } int sap(int v,int flow){ if(v==T)return flow; int rec=0; for(edge *p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f){ int ret=sap(p->t,min(flow-rec,p->f)); p->f-=ret;p->pair->f+=ret;d[v]=p; if((rec+=ret)==flow)return flow; } if(!(--gap[h[v]]))h[S]=T; gap[++h[v]]++;d[v]=g[v]; return rec; } int build(int a,int b){ int x=++tot; if(a==b)return id[a]=x; int mid=(a+b)>>1; add(x,l[x]=build(a,mid),inf),add(x,r[x]=build(mid+1,b),inf); return x; } void ask(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){add(p,x,inf);return;} int mid=(a+b)>>1; if(c<=mid)ask(l[x],a,mid,c,d,p); if(d>mid)ask(r[x],mid+1,b,c,d,p); } int main(){ scanf("%d%d",&n,&m);tot=n+m; root=build(1,1000); S=tot+1,T=S+1; for(i=1;i<=n;i++)scanf("%d%d",&spf[i][0],&spf[i][1]),add(S,i,1); for(i=1;i<=m;i++)scanf("%d%d",&x,&y),add(id[x],i+n,inf),add(i+n,T,y); for(i=1;i<=n;i++)ask(root,1,1000,spf[i][0],spf[i][1],i); for(gap[0]=T,i=1;i<=T;i++)d[i]=g[i]; while(h[S]<T)maxflow+=sap(S,inf); return printf("%d",maxflow),0; }