暑假集训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个点。

法二思路:

  匹配问题于是用匈牙利算法解决,代码短多了!!

本人因为懒惰只写了法二嘻嘻嘻

以下代码:

#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;
}
View Code

 

posted @ 2018-08-12 16:31  Jessiejzy  阅读(200)  评论(0编辑  收藏  举报