暑假集训8.7数据结构专题—网络流套线段树
题目:dtoj3848 Bajtman i Okrągły Robin
题目描述:
你是一个保安,你发现有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间进行抢劫,并计划抢走c[i]元。你在一个强盗任何一个作案的时间阻止他,你就可以挽回这个强盗带来的损失。显然,对于每个强盗,你只能挽回一次损失。不幸的是,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢?
法一思路:
匹配问题可以想到网络流,有s流向每一个时间,a[i]-b[i]的时间流向强盗,强盗流向t,流量为c[i],跑最大流。但我们发现这么样建点每个强盗需要连向一个区间的点会炸,考虑区间用线段树优化,把时间建成一颗线段树,线段树内部相连,流量为inf,于是强盗至多只需要连向logn个点。
法二思路:
匹配问题于是用匈牙利算法解决,代码短多了!!
本人因为懒惰只写了法二嘻嘻嘻
以下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=5005;int n,p,num[N],from[N],ans;struct node{int a,b,w;}t[N]; il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;return f*x;} bool cmp(node t1,node t2){return t1.w>t2.w;} bool hungary(int x){ num[x]=p; for(int i=t[x].a;i<=t[x].b;i++) if(!from[i]||(num[from[i]]!=p&&hungary(from[i]))) {from[i]=x;return 1;}return 0; } int main() { n=read();for(int i=1;i<=n;i++)t[i].a=read(),t[i].b=read()-1,t[i].w=read(); sort(t+1,t+1+n,cmp); for(int i=1;i<=n;i++){p++;if(hungary(i))ans+=t[i].w;} printf("%d\n",ans); return 0; }