您的位置:首页 > 其它

[ONTAK2015]Bajtman i Okrągły Robin

2017-03-07 15:09 337 查看

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

Time Limit: 40 Sec Memory Limit: 256 MB

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

费用流
最容易想到的建图方法:



TLE
主要是因为一个强盗向一个区间内的所有点连边,太多了
所以我们考虑优化这些连边
线段树
建图方法:



然后跑最大费用即可

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#define N 50001
#define M N*11
#define inf 1e9
using namespace std;
int n,a
,b
,c
,maxn;
int id[N*4],num,tot=1;
int src,dec,ans;
int front[N*6],from[M],next[M],to[M],cap[M],cost[M],pre[N*6];
int dis[N*6];
bool v[N*6];
int lc[N*6],rc[N*6];
queue<int>q;
struct node
{
int l,r;
}tr[N*4];
void add(int u,int v,int w,int val)
{
to[++tot]=v;next[tot]=front[u];front[u]=tot;from[tot]=u;cap[tot]=w;cost[tot]=val;
to[++tot]=u;next[tot]=front[v];front[v]=tot;from[tot]=v;cap[tot]=0;cost[tot]=-val;
}
void build(int k,int l,int r)
{
id[k]=++num;
tr[k].l=l;tr[k].r=r;
if(l==r) return;
int mid=l+r>>1;
build(k<<1,l,mid);
build((k<<1)+1,mid+1,r);
add(id[k<<1],id[k],mid-l+1,0);
add(id[(k<<1)+1],id[k],r-mid,0);
}
void insert(int k,int l,int r,int wh)
{
if(tr[k].l==l&&tr[k].r==r)
{
add(wh,id[k],1,c[wh-num]);
return;
}
int mid=tr[k].l+tr[k].r>>1;
if(r<=mid) insert(k<<1,l,r,wh);
else if(l>mid) insert((k<<1)+1,l,r,wh);
else {insert(k<<1,l,mid,wh);insert((k<<1)+1,mid+1,r,wh);}
}
bool spfa()
{
memset(dis,-127,sizeof(dis));
q.push(src);v[src]=true;dis[src]=0;
while(!q.empty())
{
int now=q.front();q.pop();v[now]=false;
for(int i=front[now];i;i=next[i])
{
int t=to[i];
if(dis[t]<dis[now]+cost[i]&&cap[i]>0)
{
dis[t]=dis[now]+cost[i];
pre[t]=i;
if(!v[t])
{
q.push(t);
v[t]=true;
}
}
}
}
return dis[dec]>0;
}
void mcmf()
{
while(spfa())
{
int tmp=inf;
for(int i=pre[dec];i;i=pre[from[i]]) tmp=min(tmp,cap[i]);
for(int i=pre[dec];i;i=pre[from[i]])
{
cap[i]-=tmp;cap[i^1]+=tmp;
}
ans+=tmp*dis[dec];
}
printf("%d",ans);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i],&b[i],&c[i]);
b[i]--;
maxn=max(maxn,b[i]);
}
dec=n*6-1;
build(1,1,maxn);
for(int i=1;i<=n;i++)
add(src,num+i,1,0);
add(1,dec,maxn,0);
for(int i=1;i<=n;i++)
insert(1,a[i],b[i],i+num);
mcmf();
}


dis数组开始初始化为-1,应该是-inf,因为反向弧的费用为负值,未访问过的点要足够小才能完成回流
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: