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