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;

}

  

你可能感兴趣的:(USACO)