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

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

 

posted @ 2018-06-20 10:07  fcwww  阅读(188)  评论(0编辑  收藏  举报