BZOJ 4276 ONTAK2015 Bajtman i Okrągły Robin

4276: [ONTAK2015]Bajtman i Okrągły Robin

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 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

Sample Output

90

HINT

 

Source

By Claris

真是一道神题,我们考虑最大费用最大流,如果裸的建图的话,好像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;
}

  

posted @ 2018-05-18 22:59  zhangenming  阅读(213)  评论(0编辑  收藏  举报