【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流

【BZOJ4276】[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

题解:建图方法很简单,直接上了:

1.S -> 每个时间点i  费用0,容量1
2.[a,b]中的所有时间点 -> 盗贼j 费用0,容量1
3.盗贼j -> T 费用c,容量1

发现边数太多,用线段树优化建图即可。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define lson x<<1
#define rson x<<1|1
using namespace std;
int S,T,cnt,n,m,now,ans,L,R;
int to[3000000],next[3000000],cost[3000000],flow[3000000],head[100000],dis[100000],inq[100000];
int pv[100000],pe[100000],A[100000],B[100000],C[100000];
queue<int> q;
void add(int a,int b,int c,int d)
{
	to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
void build(int l,int r,int x)
{
	if(l==r)
	{
		add(S,x,0,1),now=max(now,x);
		return ;
	}
	int mid=l+r>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	add(lson,x,0,mid-l+1),add(rson,x,0,r-mid);
}
void updata(int l,int r,int x,int a,int b)
{
	if(a<=l&&r<=b)
	{
		add(x,now,0,1);
		return ;
	}
	int mid=l+r>>1;
	if(a<=mid)	updata(l,mid,lson,a,b);
	if(b>mid)	updata(mid+1,r,rson,a,b);
}
int bfs()
{
	memset(dis,0x3f,sizeof(dis));
	int i,u;
	dis[S]=0,q.push(S);
	while(!q.empty())
	{
		u=q.front(),q.pop(),inq[u]=0;
		for(i=head[u];i!=-1;i=next[i])
		{
			if(dis[to[i]]>dis[u]+cost[i]&&flow[i])
			{
				dis[to[i]]=dis[u]+cost[i],pv[to[i]]=u,pe[to[i]]=i;
				if(!inq[to[i]])	inq[to[i]]=1,q.push(to[i]);
			}
		}
	}
	return dis[T]<0x3f3f3f3f;
}
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,a,b,c;
	S=0,L=5000,R=1;
	memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)	A[i]=rd(),B[i]=rd()-1,C[i]=-rd(),L=min(L,A[i]),R=max(R,B[i]);
	build(L,R,1);
	T=n+now+1;
	for(i=1;i<=n;i++)	now++,updata(L,R,1,A[i],B[i]),add(now,T,C[i],1);
	while(bfs())
	{
		int mf=1<<30;
		for(i=T;i!=S;i=pv[i])	mf=min(mf,flow[pe[i]]);
		ans+=mf*dis[T];
		for(i=T;i!=S;i=pv[i])	flow[pe[i]]-=mf,flow[pe[i]^1]+=mf;
	}
	printf("%d",-ans);
	return 0;
}

 

posted @ 2017-07-02 15:41  CQzhangyu  阅读(315)  评论(0编辑  收藏  举报