您的位置:首页 > 其它

BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流

2018-06-20 10:07 330 查看

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

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
,to[M],nxt[M],flow[M],cnt=1,val[M];
int ls
,rs
,tot=2,S=1,T=2,Q
,l,r,inq
,dis
,path
,n,maxl,aa
,bb
,cc
;
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

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

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: