bzoj3206 [Apio2013]道路费用

Posted wfj_2048

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3206 [Apio2013]道路费用相关的知识,希望对你有一定的参考价值。

Description

技术分享

Input

第一行包含三个由空格隔开的整数N,M和K。接下来的 M行描述最开始的M 条道路
。这M行中的第i行包含由空格隔开的整数ai,bi和c i,表示有一条在a i和b i之间,费用为c i的双向道路。接下
来的K行描述新建的K条道路。这 K行中的第i行包含由空格隔开的整数 xi和yi,表示有一条连接城镇xi和yi新道路
。最后一行包含N个由空格隔开的整数,其中的第j个为pj,表示从城镇j 前往城镇 1的人数。输入也满足以下约束
条件。1 ≤ N ≤ 100000;1 ≤ K ≤ 20;1 ≤ M ≤ 300000;对每个i和j,1 ≤ ci, pj ≤ 10^6;

Output

你的程序必须输出恰好一个整数到标准输出,表示能获得的最大的收入。

Sample Input

5 5 1
3 5 2
1 2 3
2 3 5
2 4 4
4 3 6
1 3
10 20 30 40 50

Sample Output

400

HINT

在样例中, Mr. Greedy应该将新道路(1,3)的费用设置为 5分钱。在这个费用下,他可以选择道路(3,5),(1,2),(2,4)和(1,3)来最小化总费用,这个费用为   14。从城镇 3出发的 30个人和从城镇 5出发的 50个人将经过新道路前往城镇 1,因此他可以获得为(30+50)_5=400 分钱的最好收入。如果我们这样做,将新道路(1,3)的费用设置为 10分钱。根据传统的限制,Mr. Greedy必须选择(3,5),(1,2),(2,4)和(2,3),因为这是唯一费用最小的集合。因此,在嘉年华的过程中道路(1,3)将没有任何收入。

 

正解:最小生成树+搜索。

这道题还是有点码的,我写了好久。。

首先$k\leq20$,我们可以想到枚举选边的集合,然后计算答案。

但是有一个问题,原图特别大,我们每次选边计算答案肯定不行,怎么办呢?

我们可以发现,有一些边是无论如何都会在原图上的,我们只要强制把$k$条边先加进去,再看有哪些边可以和这$k$条边构成最小生成树就行了。

然后我们可以把原图缩点变成一个$k+1$个点的图,但是边数还是$k^{2}$级别的。

那么我们可以再去掉那$k$条边,做一遍最小生成树,这样的边是会出现在原图上的,其他边肯定不会在图上,然后边数就变成$k$条了。

然后我们枚举$k$条边是否在图上,强制把搜索出来的边加进图中,再看这些边的取值。

只要把没加进图的边在树上走一下,经过的边边权取个$min$就行了。

 

  1 #include <bits/stdc++.h>
  2 #define il inline
  3 #define RG register
  4 #define ll long long
  5 #define N (300010)
  6 
  7 using namespace std;
  8 
  9 struct E{ int u,v,w; }gg[N],g[N],e[N];
 10 
 11 int bel[N],a[N],st[N],fa[N],vis[N],n,m,k,top,cnt,ecnt;
 12 ll val[N],ans;
 13 
 14 il int gi(){
 15   RG int x=0,q=1; RG char ch=getchar();
 16   while ((ch<0 || ch>9) && ch!=-) ch=getchar();
 17   if (ch==-) q=-1,ch=getchar();
 18   while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar();
 19   return q*x;
 20 }
 21 
 22 il int cmp(const E &a,const E &b){ return a.w<b.w; }
 23 
 24 il int find(RG int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); }
 25 
 26 struct graph{
 27   
 28   struct edge{ int nt,to,fg; }g[N<<1];
 29   
 30   int head[N],fa[N],dep[N],dis[N],num;
 31   ll sz[N];
 32   
 33   il void insert(RG int from,RG int to,RG int fg){
 34     g[++num]=(edge){head[from],to,fg},head[from]=num; return;
 35   }
 36   
 37   il void dfs1(RG int x,RG int p){
 38     if (!bel[x]) bel[x]=++cnt; val[bel[x]]+=a[x]; RG int v;
 39     for (RG int i=head[x];i;i=g[i].nt){
 40       v=g[i].to; if (v==p) continue;
 41       if (g[i].fg) bel[v]=bel[x]; dfs1(v,x);
 42     }
 43     return;
 44   }
 45   
 46   il void dfs2(RG int x,RG int p){
 47     fa[x]=p,dep[x]=dep[p]+1,sz[x]=val[x],dis[x]=1<<30; RG int v;
 48     for (RG int i=head[x];i;i=g[i].nt){
 49       v=g[i].to; if (v==p) continue;
 50       dfs2(v,x),sz[x]+=sz[v];
 51     }
 52     return;
 53   }
 54   
 55   il void getlca(RG int u,RG int v,RG int w){
 56     while (u!=v){
 57       if (dep[u]<dep[v]) swap(u,v);
 58       dis[u]=min(dis[u],w),u=fa[u];
 59     }
 60     return;
 61   }
 62   
 63   il ll getans(RG int x,RG int p){
 64     RG ll res=0; RG int v;
 65     for (RG int i=head[x];i;i=g[i].nt){
 66       v=g[i].to; if (v==p) continue;
 67       res+=getans(v,x)+1LL*(!g[i].fg)*dis[v]*sz[v];
 68     }
 69     return res;
 70   }
 71   
 72 }G;
 73 
 74 il ll check(){
 75   for (RG int i=1;i<=cnt;++i) fa[i]=i,G.head[i]=0; G.num=0;
 76   for (RG int i=1,x,y;i<=top;++i){
 77     x=find(e[st[i]].u),y=find(e[st[i]].v);
 78     if (x!=y) fa[x]=y,G.insert(e[st[i]].u,e[st[i]].v,0),G.insert(e[st[i]].v,e[st[i]].u,0);
 79   }
 80   for (RG int i=1,x,y;i<=m;++i){
 81     x=find(g[i].u),y=find(g[i].v),vis[i]=0;
 82     if (x!=y) fa[x]=y,vis[i]=1,G.insert(g[i].u,g[i].v,1),G.insert(g[i].v,g[i].u,1);
 83   }
 84   G.dfs2(1,0);
 85   for (RG int i=1;i<=m;++i) if (!vis[i]) G.getlca(g[i].u,g[i].v,g[i].w);
 86   return G.getans(1,0);
 87 }
 88 
 89 il void dfs(RG int x){
 90   if (x>k) ans=max(ans,check());
 91   else st[++top]=x,dfs(x+1),--top,dfs(x+1); return;
 92 }
 93 
 94 int main(){
 95 #ifndef ONLINE_JUDGE
 96   freopen("toll.in","r",stdin);
 97   freopen("toll.out","w",stdout);
 98 #endif
 99   n=gi(),m=gi(),k=gi(); for (RG int i=1;i<=n;++i) fa[i]=i;
100   for (RG int i=1;i<=m;++i) g[i].u=gi(),g[i].v=gi(),g[i].w=gi();
101   for (RG int i=1,x,y;i<=k;++i){
102     e[i].u=gi(),e[i].v=gi(),x=find(e[i].u),y=find(e[i].v);
103     if (x!=y) fa[x]=y,G.insert(e[i].u,e[i].v,0),G.insert(e[i].v,e[i].u,0);
104   }
105   sort(g+1,g+m+1,cmp);
106   for (RG int i=1,x,y;i<=m;++i){
107     x=find(g[i].u),y=find(g[i].v);
108     if (x!=y) fa[x]=y,vis[i]=1,G.insert(g[i].u,g[i].v,1),G.insert(g[i].v,g[i].u,1);
109   }
110   for (RG int i=1;i<=n;++i) a[i]=gi(),fa[i]=i; G.dfs1(1,0);
111   for (RG int i=1;i<=k;++i) e[i].u=bel[e[i].u],e[i].v=bel[e[i].v];
112   for (RG int i=1,x,y;i<=m;++i){
113     g[i].u=bel[g[i].u],g[i].v=bel[g[i].v];
114     x=find(g[i].u),y=find(g[i].v),vis[i]=0;
115     if (x!=y) fa[x]=y,vis[i]=1,gg[++ecnt]=g[i];
116   }
117   m=ecnt; for (RG int i=1;i<=m;++i) g[i]=gg[i];
118   dfs(1),cout<<ans; return 0;
119 }

 

以上是关于bzoj3206 [Apio2013]道路费用的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3206 [Apio2013]道路费用

bzoj 3206: [Apio2013]道路费用最小生成树+并查集

[APIO2013]道路费用

APIO2013道路费用(TOLL)

bzoj3624: [Apio2008]免费道路

bzoj3624,[Apio2008]免费道路