其他分享
首页 > 其他分享> > 【bzoj3218】a+b Problem 最小割+主席树

【bzoj3218】a+b Problem 最小割+主席树

作者:互联网

数据范围:$n≤5000$,$a,l,r≤10^9$,$b,w,p≤2\times 10^5$。

 

我们考虑一种暴力的最小割做法:

首先令$sum=\sum\limits_{i=1}^{n} b_i+w_i$

 

我们建一个图:

$S->i$,边权为$w_i$

$i->T$,边权为$b_i$

$i->i'$,边权为$p_i$

$j->i'$,边权为$∞$,(这里的i和j需要满足题目中的i,j限制)

然后我们对这个图跑一遍最小割,将$sum$减去这个值输出就是答案了。

这么建图总共需要$2n+2$个点,$O(n^2)$条边

 1 #include<bits/stdc++.h>
 2 #define M 1000005
 3 #define N 150005
 4 #define INF 19890604
 5 using namespace std;
 6 
 7 struct edge{int u,v,next;}e[M]={0}; int head[N]={0},use=0;
 8 void add(int x,int y,int z){e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use++;}
 9 void ADD(int x,int y,int z){add(x,y,z); add(y,x,0);}
10 
11 int dis[N]={0},S,T; queue<int> q;
12 
13 bool bfs(){
14     memset(dis,0,sizeof(dis));
15     q.push(S); dis[S]=1;
16     while(!q.empty()){
17         int u=q.front(); q.pop();
18         for(int i=head[u];~i;i=e[i].next)
19         if(e[i].v&&dis[e[i].u]==0){
20             dis[e[i].u]=dis[u]+1;
21             q.push(e[i].u);
22         }
23     }
24     return dis[T];
25 }
26 
27 int dfs(int x,int flow){
28     if(x==T) return flow; int sum=0;
29     for(int i=head[x];~i;i=e[i].next)
30     if(e[i].v&&dis[x]+1==dis[e[i].u]){
31         int k=dfs(e[i].u,min(flow,e[i].v));
32         e[i].v-=k; e[i^1].v+=k;
33         sum+=k; flow-=k;
34         if(flow==0) return sum;
35     }
36     if(flow==0) dis[x]=-1;
37     return sum;
38 }
39 
40 int dinic(){
41     int res=0; 
42     while(bfs()) 
43     res+=dfs(S,1<<30); 
44 return res;}
45 
46 int n,sum=0;
47 int a[N]={0},b[N]={0},w[N]={0},l[N]={0},r[N]={0},p[N]={0},ok[N]={0};
48 
49 int main(){
50     scanf("%d",&n);
51     for(int i=1;i<=n;i++){
52         scanf("%d%d%d%d%d%d",a+i,b+i,w+i,l+i,r+i,p+i);
53         sum+=b[i]+w[i];
54     }
55     S=0,T=2*n+1;
56     memset(head,-1,sizeof(head));
57     for(int i=1;i<=n;i++) ADD(S,i,w[i]),ADD(i,T,b[i]),ADD(i+n,i,p[i]);
58     for(int i=1;i<=n;i++) for(int j=1;j<i;j++)
59     if(l[i]<=a[j]&&a[j]<=r[i])
60     ADD(j,i+n,INF);
61     cout<<sum-dinic()<<endl;
62 }    
暴力

 

然后这个做法显然是会MLE的

我们发现原先的限制条件相当于在二维平面上框出一个允许的区间。

对于这种约束,我们可以用主席树来实现约束。

然后随便搞一搞就没了,注意细节

 1 #include<bits/stdc++.h>
 2 #define M 400000
 3 #define INF 19890604
 4 using namespace std;
 5 
 6 struct edge{int u,v,next;}e[M]={0}; int head[M]={0},use=0;
 7 void add(int x,int y,int z){e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use++;}
 8 void ADD(int x,int y,int z){add(x,y,z); add(y,x,0);}
 9 
10 int dis[M]={0},S,T; queue<int> q;
11 
12 bool bfs(){
13     memset(dis,0,sizeof(dis));
14     q.push(S); dis[S]=1;
15     while(!q.empty()){
16         int u=q.front(); q.pop();
17         for(int i=head[u];~i;i=e[i].next)
18         if(e[i].v&&dis[e[i].u]==0){
19             dis[e[i].u]=dis[u]+1;
20             q.push(e[i].u);
21         }
22     }
23     return dis[T];
24 }
25 
26 int dfs(int x,int flow){
27     if(x==T) return flow; int sum=0;
28     for(int i=head[x];~i;i=e[i].next)
29     if(e[i].v&&dis[x]+1==dis[e[i].u]){
30         int k=dfs(e[i].u,min(flow,e[i].v));
31         e[i].v-=k; e[i^1].v+=k;
32         sum+=k; flow-=k;
33         if(flow==0) return sum;
34     }
35     if(flow==0) dis[x]=-1;
36     return sum;
37 }
38 
39 int dinic(){int res=0; while(bfs()) res+=dfs(S,1<<30); return res;}
40 
41 int c[M]={0},a[M]={0},b[M]={0},w[M]={0},l[M]={0},r[M]={0},p[M]={0};
42 int lc[M]={0},rc[M]={0},cnt,rt=0,sum=0,n;
43 
44 void updata(int x,int l,int r,int ll,int rr,int id){
45     if(!x) return;
46     if(ll<=l&&r<=rr)return ADD(x,id,INF);
47     int mid=(l+r)>>1;
48     if(ll<=mid) updata(lc[x],l,mid,ll,rr,id);
49     if(mid<rr) updata(rc[x],mid+1,r,ll,rr,id);
50 }
51 void updata(int &x,int l,int r,int id,int k){
52     cnt++; lc[cnt]=lc[x]; rc[cnt]=rc[x];
53     if(x) ADD(x,cnt,INF); x=cnt;
54     ADD(k,x,INF);
55     if(l==r) return;
56     int mid=(l+r)>>1;
57     if(id<=mid) updata(lc[x],l,mid,id,k);
58     else updata(rc[x],mid+1,r,id,k);
59 }
60 
61 int main(){
62     memset(head,-1,sizeof(head));
63     scanf("%d",&n);
64     for(int i=1;i<=n;i++){
65         scanf("%d%d%d%d%d%d",a+i,b+i,w+i,l+i,r+i,p+i);
66         c[i]=a[i]; sum+=b[i]+w[i];
67     }
68     sort(c+1,c+n+1);
69     for(int i=1;i<=n;i++){
70         a[i]=lower_bound(c+1,c+n+1,a[i])-c;
71         l[i]=lower_bound(c+1,c+n+1,l[i])-c;
72         r[i]=upper_bound(c+1,c+n+1,r[i])-c-1;
73     }
74     S=0; T=2*n+1; cnt=2*n+1;
75     for(int i=1;i<=n;i++){
76         ADD(S,i,w[i]);
77         ADD(i,T,b[i]);
78         ADD(i+n,i,p[i]);
79         if(l[i]<=r[i]) updata(rt,1,n,l[i],r[i],i+n);
80         updata(rt,1,n,a[i],i);
81     }
82     cout<<sum-dinic()<<endl;
83 }

标签:use,int,sum,flow,最小,bzoj3218,Problem,head,dis
来源: https://www.cnblogs.com/xiefengze1/p/10599919.html