BZOJ1707 : [Usaco2007 Nov]tanning分配防晒霜

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;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/4592381.html