BZOJ4276 : [ONTAK2015]Bajtman i Okrągły Robin

建立线段树,

S向每个叶子连边,容量1,费用0。

孩子向父亲连边,容量inf,费用0。

每个强盗向T连边,容量1,费用为c[i]。

对应区间内的点向每个强盗,容量1,费用0。

求最大费用流即可。

 

#include<cstdio>
const int inf=~0U>>2,N=15010,M=1000000;
int n,i,A,B,C,ans,cl[N],cr[N],tot=1;unsigned short l,r;
int u[M],v[M],c[M],co[M],nxt[M],t=1,S,T=1,q[65536],g[N],f[N],d[N];bool in[N];
inline void add(int x,int y,int z,int zo){
  u[++t]=x;v[t]=y;c[t]=z;co[t]=zo;nxt[t]=g[x];g[x]=t;
  u[++t]=y;v[t]=x;c[t]=0;co[t]=-zo;nxt[t]=g[y];g[y]=t;
}
inline bool spfa(){
  int x,i;
  for(i=1;i<=tot;i++)d[i]=-inf,in[i]=0;
  d[S]=0;in[S]=1;q[l=r=0]=S;
  while(l!=r+1){
    int x=q[l++];
    if(x==T)continue;
    for(i=g[x];i;i=nxt[i])if(c[i]&&co[i]+d[x]>d[v[i]]){
      int y=v[i];
      d[y]=co[i]+d[x];f[y]=i;
      if(!in[y]){
        in[y]=1;
        if(d[y]>d[q[l]])q[--l]=y;else q[++r]=y;
      }
    }
    in[x]=0;
  }
  return d[T]>0;
}
int build(int a,int b){
  int x=++tot;
  if(a==b)return add(S,x,1,0),x;
  int mid=(a+b)>>1;
  add(cl[x]=build(a,mid),x,inf,0);
  add(cr[x]=build(mid+1,b),x,inf,0);
  return x;
}
void addedge(int x,int a,int b){
  if(A<=a&&b<=B){add(x,tot,1,0);return;}
  int mid=(a+b)>>1;
  if(A<=mid)addedge(cl[x],a,mid);
  if(B>mid)addedge(cr[x],mid+1,b);
}
int main(){
  build(1,4999);
  for(scanf("%d",&n);n--;addedge(2,1,4999))scanf("%d%d%d",&A,&B,&C),add(++tot,T,1,C),B--;
  while(spfa())for(ans+=d[T],i=T;i!=S;i=u[f[i]])c[f[i]]--,c[f[i]^1]++;
  return printf("%d",ans),0;
}

  

posted @ 2015-09-30 15:52  Claris  阅读(487)  评论(0编辑  收藏  举报