BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流
BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流
Description
有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元。作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢?
Input
第一行包含一个正整数n(1<=n<=5000),表示强盗的个数。
接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]<=10000),依次描述每一个强盗。
Output
输出一个整数,即可以挽回的损失的最大值。
Sample Input
4
1 4 40
2 4 10
2 3 30
1 3 20
1 4 40
2 4 10
2 3 30
1 3 20
Sample Output
90
S对每个强盗连边(1,c[i]),每个强盗对所在时间连边(1,0),每个时间对T连边(1,0)。
然后跑最大费用最大流。
这是一个朴素的想法,然后我们发现强盗的时间都是一段连续的区间。
线段树优化建图,结点连向儿子(inf,0),叶子连向T,相当于多开出4n的辅助结点,主要的连边方式不变。
注意每次增广时只会使流量+1,因此不需要找一遍最小的流。
反正我不加这个优化就T了。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 25050 #define M 200050 #define inf 0x3f3f3f3f int head[N],to[M],nxt[M],flow[M],cnt=1,val[M]; int ls[N],rs[N],tot=2,S=1,T=2,Q[N],l,r,inq[N],dis[N],path[N],n,maxl,aa[N],bb[N],cc[N]; void add(int u,int v,int f,int c) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; val[cnt]=c; to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; val[cnt]=-c; } bool spfa() { memset(dis,0x80,sizeof(dis)); memset(path,0,sizeof(path)); dis[S]=0; l=r=0; Q[r++]=S; while(l!=r) { int x=Q[l++],i; inq[x]=0; if(l==tot+1) l=0; for(i=head[x];i;i=nxt[i]) { if(dis[to[i]]<dis[x]+val[i]&&flow[i]) { dis[to[i]]=dis[x]+val[i]; path[to[i]]=i^1; if(!inq[to[i]]) { inq[to[i]]=1; if(dis[to[i]]>dis[Q[l]]) { l--; if(l==-1) l=tot; Q[l]=to[i]; } else { Q[r++]=to[i]; if(r==tot+1) r=0; } } } } } return path[T]; } void mcmf() { int nf,i,ans=0; while(spfa()) { ans+=dis[T]; for(i=T;i!=S;i=to[path[i]]) { flow[path[i]^1]--; flow[path[i]]++; } } printf("%d\n",ans); } void build(int l,int r,int &p) { p=++tot; if(l==r) {add(p,T,1,0);return ;} int mid=(l+r)>>1; build(l,mid,ls[p]); build(mid+1,r,rs[p]); add(p,ls[p],inf,0); add(p,rs[p],inf,0); } void update(int l,int r,int x,int y,int p) { if(x<=l&&y>=r) { add(tot,p,1,0); return ; } int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,y,ls[p]); if(y>mid) update(mid+1,r,x,y,rs[p]); } int main() { register int i,root=0; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d%d",&aa[i],&bb[i],&cc[i]); bb[i]--; maxl=max(maxl,bb[i]); } build(1,maxl,root); for(i=1;i<=n;i++) { tot++; add(S,tot,1,cc[i]); update(1,maxl,aa[i],bb[i],root); } mcmf(); }