BZOJ 4276 [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
 
 
 
分析:
  很容易看出来一个网络流的模型,但是暴力建图一点未来都没有......
  注意到强盗出现的时间是一个连续的区间,于是可以用线段树来优化建图。(好操作啊!)

  建图:
  ·源点S,汇点T。
  ·S向所有的小偷连边,容量为1,费用为c[i]。
  ·所有小偷向对应区间连边,容量为1,费用为0。
  ·线段树的叶子向T连边,容量为1,费用为0。
  ·线段树中的点向其左右儿子连边,容量为inf,费用为0。

  最大流最大费就是答案。

  But,卡常卡死我了......

  注意两点(滑稽):

  1、为了小常数,以后网络流边的结构体不要定义from这个变量。

  2、当你想要卡常的时候,注意不要用结构体去套你的算法......全部东西都用数组吧......

  3、我也不知道为什么本机上最快的数组版本上去就T了?所以还是把过了的那个弄上来吧......

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 #define inf 1e9
 13 using namespace std;
 14 const int MAXN=5005;
 15  
 16 int N,a[MAXN],b[MAXN],c[MAXN],up,low=inf;
 17 struct edge{ int to,next,cap,flow,cost; }E[300005];
 18 int n,s,t,np=0,first[15005],dist[15005],fl[15005];
 19 int mq[15005+5],front,rear;
 20 bool inq[15005];
 21 void add_edge(int u,int v,int cap,int cost)
 22 {
 23     E[++np]=(edge){v,first[u],cap,0,cost};
 24     first[u]=np;
 25     E[++np]=(edge){u,first[v],0,0,-cost};
 26     first[v]=np;
 27 }
 28 int MCMF(){
 29     int maxcost=0,now;
 30     while(1){
 31         memset(dist,0,sizeof(dist));
 32         front=rear=0;
 33         mq[rear++]=s,inq[s]=1;
 34         while(front!=rear){
 35             int i=mq[front++]; if(front>15005) front=0;
 36             inq[i]=0;
 37             for(int p=first[i];p;p=E[p].next){
 38                 int j=E[p].to;
 39                 if(E[p].cap>E[p].flow&&dist[i]+E[p].cost>dist[j]){
 40                     dist[j]=dist[i]+E[p].cost;
 41                     fl[j]=p;
 42                     if(!inq[j]){
 43                         mq[rear++]=j,inq[j]=1;
 44                         if(rear>15005) rear=0;
 45                     }
 46                 }
 47             }
 48         }
 49         if(dist[t]<=0) break;
 50         now=t,maxcost+=dist[t];
 51         while(now!=s){
 52             E[fl[now]].flow++,E[(fl[now]-1^1)+1].flow--;
 53             now=E[(fl[now]-1^1)+1].to;
 54         }
 55     }
 56     return maxcost;
 57 }
 58      
 59 int rt=0,np2=0,lc[10005],rc[10005];
 60 void build(int &now,int L,int R){
 61     now=++np2;
 62     if(L==R){
 63         add_edge(now+N,t,1,0);
 64         return;
 65     }
 66     int m=L+R>>1;
 67     build(lc[now],L,m);
 68     build(rc[now],m+1,R);
 69     add_edge(now+N,lc[now]+N,inf,0);
 70     add_edge(now+N,rc[now]+N,inf,0);
 71 }
 72 void update(int now,int L,int R,int A,int B,int id){
 73     if(A<=L&&R<=B){
 74         add_edge(id,now+N,1,0);
 75         return;
 76     }
 77     int m=L+R>>1;
 78     if(B<=m) update(lc[now],L,m,A,B,id);
 79     else if(A>m) update(rc[now],m+1,R,A,B,id);
 80     else update(lc[now],L,m,A,B,id),update(rc[now],m+1,R,A,B,id);
 81 }
 82  
 83 void _scanf(int &x)
 84 {
 85     x=0;
 86     char ch=getchar();
 87     while(ch<'0'||ch>'9') ch=getchar();
 88     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
 89 }
 90 void data_in()
 91 {
 92     _scanf(N);
 93     for(int i=1;i<=N;i++){
 94         _scanf(a[i]);_scanf(b[i]);_scanf(c[i]);
 95         up=max(up,b[i]),low=min(low,a[i]);
 96     }
 97 }
 98 void work()
 99 {
100     n=2*(up-low)+N+5,s=n-1,t=n;
101     build(rt,low,up-1);
102     for(int i=1;i<=N;i++){
103         update(rt,low,up-1,a[i],b[i]-1,i);
104         add_edge(s,i,1,c[i]);
105     }
106     printf("%d\n",MCMF());
107 }
108 int main()
109 {
110     data_in();
111     work();
112     return 0;
113 }
View Code

 

posted @ 2018-03-28 11:14  KKKorange  阅读(103)  评论(0编辑  收藏  举报