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
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 }