BZOJ 4276 ONTAK2015 Bajtman i Okrągły Robin
4276: [ONTAK2015]Bajtman i Okrągły Robin
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 622 Solved: 306
[Submit][Status][Discuss]
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
HINT
Source
真是一道神题,我们考虑最大费用最大流,如果裸的建图的话,好像zkw的复杂度承受不了 那么我们考虑线段树优化建图
s向每个盗贼连一条容量为1,费用为c[i]的边,每个盗贼向线段树上所拆出来的节点连一条容量为1,费用为0的边,线段树上的每个节点向子节点连一条容量为inf,费用为0的边
叶节点向t连一条容量为1,费用为0的边,最后跑最大费用最大流即可
#include <bits/stdc++.h> #define ll long long #define inf 1e9+10 using namespace std; inline int read(){ int x=0;int f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=1e5+10; struct node{ int y,next,flow,back,w; }e[MAXN*20]; int linkk[MAXN*20],len=0,n,s,t,dis[21000],vis[21000],x,y,ans=0,xx[MAXN],yy[MAXN],k[MAXN]; inline void insert(int x,int y,int f,int c){ e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;e[len].flow=f;e[len].back=len+1;e[len].w=c; e[++len].y=x;e[len].next=linkk[y];linkk[y]=len;e[len].flow=0;e[len].back=len-1;e[len].w=-c; } inline void get(int rt,int l,int r,int i){ if(l>y||r<x) return; if(l>=x&&r<=y){ insert(i+1,n+rt+1,1,0);return; } int mid=(l+r)>>1; get(rt<<1,l,mid,i); get(rt<<1|1,mid+1,r,i); } inline void build(int rt,int l,int r){ if(l==r){ insert(rt+n+1,t,1,0); return; } insert(rt+n+1,(rt<<1)+n+1,inf,0); insert(rt+n+1,(rt<<1|1)+n+1,inf,0); int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } inline bool getdis(){ memset(dis,-1,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[t]=0;vis[t]=1;deque<int>q; q.push_back(t); while(!q.empty()){ int tn=q.front();q.pop_front(); for(int i=linkk[tn];i;i=e[i].next){ if(e[e[i].back].flow&&dis[e[i].y]<dis[tn]-e[i].w){ dis[e[i].y]=dis[tn]-e[i].w; if(!vis[e[i].y]){ if(!q.empty()&&dis[e[i].y]>dis[q.front()]) q.push_front(e[i].y); else q.push_back(e[i].y); } } } vis[tn]=0; } return dis[s]>=0; } inline int getcost(int x,int flow){ int d,f=0;vis[x]=1; if(x==t) return flow; for(int i=linkk[x];i;i=e[i].next){ if(e[i].flow&&!vis[e[i].y]&&dis[e[i].y]==dis[x]-e[i].w){ if(d=getcost(e[i].y,min(e[i].flow,flow-f))){ f+=d;e[i].flow-=d;e[e[i].back].flow+=d; ans+=e[i].w*d;if(f==flow) return flow; } } } return f; } inline void zkw(){ while(getdis()){ vis[t]=1; while(vis[t]){ memset(vis,0,sizeof(vis)); getcost(s,inf); } } } int main(){ //freopen("All.in","r",stdin); //freopen("zh.out","w",stdout); n=read();s=0;int maxn=0;t=1; for(int i=1;i<=n;i++){ xx[i]=read();yy[i]=read()-1;k[i]=read(); maxn=max(maxn,yy[i]); } for(int i=1;i<=n;i++){ x=xx[i];y=yy[i]; insert(s,i+1,1,k[i]); get(1,1,maxn,i); } build(1,1,maxn); zkw(); cout<<ans<<endl; return 0; }