[bzoj4276][ONTAK2015]Bajtman i Okrągły Robin
2015-10-26 16:49
525 查看
4276: [ONTAK2015]Bajtman i Okrągły Robin
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 77 Solved: 39
[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],ci,依次描述每一个强盗。
Output
输出一个整数,即可以挽回的损失的最大值。
Sample Input
4
1 4 40
2 4 10
2 3 30
1 3 20
Sample Output
90
题解:
首先很明显的可以看出来个可以跑费用流,可以建两排点,一排是所有的人,一排是时间min-max。我们从源点向每个人连<1,0>的边,从每个人向他们的时间连<1,c[i]>的边,从每个时间向汇点连<1,0>的边。然后跑费用流就行。
但是上面的这种方法的点有n*2+2个,边是n^2级别的,显然不行。那这样我们就需要优化一下。
其实每个人所能作案的时间是一个时间段也就是一个区间,那么我们能不能将这个时间段划分成几个小的来连边,这样就减少了边的数量。这样我们就想到了线段树可以将区间裂开。
所以我们以所有输入的区间的最小值和最大值建一棵线段树。
从源点向每个人连<1,c[i]>的边。
从线段树的每个父亲节点向他的子节点连
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define T 2 #define inf 0x7fffffff const int N=5010; const int M=100000; bool f[M]; struct S{int st,en,va,co;}aa[M*20]; int n,a ,b ,c ,tot=1,point[M],next[M*20],dis[M],pre[M],l[M*20]; inline int in(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } inline void add(int x,int y,int va,int co){ tot+=1;next[tot]=point[x];point[x]=tot; aa[tot].st=x;aa[tot].en=y;aa[tot].va=va;aa[tot].co=co; tot+=1;next[tot]=point[y];point[y]=tot; aa[tot].st=y;aa[tot].en=x;aa[tot].va=0;aa[tot].co=-co; } #define mid (l+r)/2 #define L k<<1,l,mid #define R k<<1|1,mid+1,r inline void build_1(int k,int l,int r){ if(l==r){ add(k+2+n,T,1,0); return ; } add(n+2+k,n+2+(k<<1),inf,0); add(n+2+k,n+2+(k<<1|1),inf,0); build_1(L); build_1(R); } inline void build_2(int k,int l,int r,int x,int y,int z){ if(x<=l&&y>=r){ add(z+2,n+2+k,inf,0); return ; } if(x<=mid) build_2(L,x,y,z); if(y>mid) build_2(R,x,y,z); } inline int SPFA(int x,int y){ int i,u,h,t; memset(f,1,sizeof(f)); memset(pre,0,sizeof(pre)); for(i=1;i<=M;++i) dis[i]=-1; h=t=1;l[h]=x;dis[x]=0; while(h<=t){ u=l[h]; f[u]=true; for(i=point[u];i;i=next[i]) if(aa[i].va&&dis[aa[i].en]<dis[u]+aa[i].co){ dis[aa[i].en]=dis[u]+aa[i].co; pre[aa[i].en]=i; if(f[aa[i].en]){ f[aa[i].en]=false; if(dis[aa[i].en]>dis[l[h+1]]) l[h--]=aa[i].en; else l[++t]=aa[i].en; } } h+=1; } return dis[y]; } inline int ISAP(int x,int y){ int i,minn=inf; for(i=y;i!=x;i=aa[pre[i]].st) minn=min(minn,aa[pre[i]].va); for(i=y;i!=x;i=aa[pre[i]].st){ aa[pre[i]].va-=minn; aa[pre[i]^1].va+=minn; } return minn; } int main(){ int i,j,r=0,l=inf; n=in(); for(i=1;i<=n;++i){ a[i]=in();b[i]=in();c[i]=in(); b[i]-=1; r=max(r,b[i]); l=min(l,a[i]); } build_1(1,l,r); for(i=1;i<=n;++i){ add(1,i+2,1,c[i]); build_2(1,l,r,a[i],b[i],i); } int minn,ans=0; while(minn!=-1){ minn=SPFA(1,T); if(minn!=-1) ans+=minn*ISAP(1,T); } printf("%d\n",ans); }
相关文章推荐
- 第八周项目3--顺序串算法
- 第八周项目2 - 建立链串的算法库
- Android UI开发第三篇-PopupWindow
- saltstock 多master 普通用户
- 详解JavaScript编程中的window与window.screen对象
- int 转 string
- 【bzoj2953】【poi2002】【商务旅行】【树上倍增】
- Kendo 锁定元素并显示加载动画
- 远程连接服务器无法拷贝本地文件解决(远程桌面无法复制文件)
- 采用dlopen、dlsym、dlclose加载动态链接库【总结】
- 归档与反归档(ios数据持久化)
- javascript中的关键字和保留字
- codis集群使用经验
- 第七周实践项目~建立链队算法库
- 阿里PM的可用性测试秘籍:有理有据的用户体验优化
- iOS开发系列--通知与消息机制
- 美团Android资源混淆保护实践
- 优先级反转问题的和解决方法
- IOS--- Segue区别及视图的切换
- react native 环境搭建(iOS)