正题

题目链接:https://www.luogu.com.cn/problem/P3639


题目大意

给出nnn个点mmm条有边权的无向图,然后再给出kkk条边权未定义的边,然后每个点有一个人数pip_ipi​。

现在要你给未确定的边权的边确定边权然后选出图的一棵最小生成树,之后所有点上的人都从自己的点走到根节点,当一个人经过刚刚确定边权的边时会支付这条边的权值的费用,现在要求总费用和最大。

保证mmm条边的图联通且权值互不相同。

1≤n≤105,1≤m≤3×105,1≤k≤201\leq n\leq 10^5,1\leq m\leq 3\times 10^5,1\leq k\leq 201≤n≤105,1≤m≤3×105,1≤k≤20


解题思路

突破口肯定在于权值互不相同,因为这样的话最小生成树就唯一了,然后发现我们加上kkk条边后最多替换掉原来图上的kkk条边,所以大部分的边都是和原来的相同的。

我们可以先把这kkk条边连接上,然后跑一棵最小生成树,再吧这kkk条边去掉这样就最多会产生k+1k+1k+1个连通块。

然后再用联通块跑一次最小生成树,把这些边记下来,这些边是可能使用上的。

之后我们2k2^k2k枚举哪些边选不选入最小生成树上,然后拿上面的边跑最小生成树,之后每条边的权值就是所有连接分割的两个联通块的最小边权,这个我们可以枚举边然后直接暴力跳,之后统计答案就好了。

时间复杂度:O(mlog⁡m+2kk2)O(m\log m+2^kk^2)O(mlogm+2kk2)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const ll N=3e5+10,K=22;
struct edge{ll x,y,w;
}e[N];
ll n,m,k,cnt,answer,p[N],fa[N],fb[N],rev[N];
ll r[K],w[K],dep[K],f[K],dx[K],dy[K],mn[K];
vector<int>G[K];ll a[K][K];
bool cmp(edge x,edge y)
{return x.w<y.w;}
ll find(ll x)
{return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
ll finb(ll x)
{return (fb[x]==x)?x:(fb[x]=finb(fb[x]));}
void dfs(ll x,ll fa){r[x]=w[x];f[x]=fa;dep[x]=dep[fa]+1;for(ll i=0;i<G[x].size();i++){ll y=G[x][i];if(y==fa)continue;dfs(y,x);r[x]+=r[y];}return;
}
signed main()
{scanf("%lld%lld%lld",&n,&m,&k);for(ll i=1;i<=m;i++){ll x,y,w;scanf("%lld%lld%lld",&x,&y,&w);e[i]=(edge){x,y,w};}sort(e+1,e+1+m,cmp);for(ll i=1;i<=n;i++)fa[i]=fb[i]=i;for(ll i=0;i<k;i++){scanf("%lld%lld",&dx[i],&dy[i]);ll x=find(dx[i]),y=find(dy[i]);if(x==y)continue;fa[x]=y;}for(ll i=1;i<=n;i++)scanf("%lld",&p[i]);for(ll i=1;i<=m;i++){ll x=e[i].x,y=e[i].y;x=find(x);y=find(y);if(x==y)continue;fa[x]=y;fb[finb(e[i].x)]=finb(e[i].y);}for(ll i=1;i<=n;i++)if(finb(i)==i)rev[i]=++cnt,fa[cnt]=cnt;for(ll i=1;i<=n;i++)rev[i]=rev[finb(i)];for(ll i=1;i<=n;i++)w[rev[i]]+=p[i];memset(a,0x3f,sizeof(a));int pm=m;m=0;for(ll i=1;i<=pm;i++){ll x=e[i].x,y=e[i].y,w=e[i].w;x=rev[x];y=rev[y];if(find(x)==find(y))continue;fa[find(x)]=find(y);e[++m]=(edge){x,y,w};}sort(e+1,e+1+m,cmp);ll MS=(1<<k);for(ll i=0;i<k;i++)dx[i]=rev[dx[i]],dy[i]=rev[dy[i]];for(ll s=0;s<MS;s++){memset(mn,0x3f,sizeof(mn));for(ll i=1;i<=cnt;i++)fa[i]=i,G[i].clear();bool flag=0;for(ll i=0;i<k;i++){if(!((s>>i)&1))continue;ll x=find(dx[i]),y=find(dy[i]);if(x==y){flag=1;break;}fa[x]=y;G[dx[i]].push_back(dy[i]);G[dy[i]].push_back(dx[i]);}if(flag)continue;for(ll i=1;i<=m;i++){ll x=find(e[i].x),y=find(e[i].y);if(x==y)continue;fa[x]=y;G[e[i].x].push_back(e[i].y);G[e[i].y].push_back(e[i].x);}dfs(rev[1],0);for(ll i=1;i<=m;i++){ll x=e[i].x,y=e[i].y;while(x!=y){if(dep[x]<dep[y])swap(x,y);mn[x]=min(mn[x],e[i].w);x=f[x];}}ll ans=0;for(ll i=0;i<k;i++){if(!((s>>i)&1))continue;ll x=dx[i],y=dy[i];if(dep[x]<dep[y])swap(x,y);ans+=mn[x]*r[x];}answer=max(answer,ans);}printf("%lld\n",answer);return 0;
}

P3639-[APIO2013]道路费用【最小生成树】相关推荐

  1. [BZOJ3206][Apio2013]道路费用

    [BZOJ3206][Apio2013]道路费用 试题描述 输入 第一行包含三个由空格隔开的整数N,M和K.接下来的 M行描述最开始的M 条道路.这M行中的第i行包含由空格隔开的整数ai,bi和c i ...

  2. [APIO2013]道路费用

    Description 给定一张无向连通图,存在边权ccc与点权a" role="presentation">aaa. 加入KKK条特殊边,构造出这些边的边权使得存 ...

  3. APIO2013 道路费用

    题目链接 大意是说,调整k条特殊边边的值,并在原图的基础上构建最小生成树.使得经过所有特殊边的值之和最大. 感谢dasxxx学长指出题目要素(加上新边,两点之间最多只有一条边),请各位在理解下文解法时 ...

  4. bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路(最小生成树)

    1626: [Usaco2007 Dec]Building Roads 修建道路 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1709  Solved ...

  5. Jungle Roads丛林道路(最小生成树PrimKruskal算法)

    Jungle Roads丛林道路 POJ - 1251 目录 Jungle Roads丛林道路 题意描述 Kruskal算法解题思路 Kruskal AC代码 Prim 解题思路 AC代码 The H ...

  6. jzoj100042-保留道路【最小生成树,图论】

    正题 题目大意 一张无向图,求剩下一些边使图联通且wG∗max{gVi}+wS∗max{sVi}wG*max\{g_{V_i}\}+wS*max\{s_{V_i}\}wG∗max{gVi​​}+wS∗ ...

  7. 修建道路(最小生成树)

    N个村庄,从1到N编号,现在请您兴建一些路使得任何两个村庄彼此连通.我们称村庄A和B是连通的,当且仅当在A和B之间存在一条路,或者存在一个存在C,使得A和C之间有一条路,并且C和B是连通的. 已知在一 ...

  8. PKUSC2018训练日程(4.18~5.30)

    (总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...

  9. [总结]2019年9月 OI学习/刷题记录

    从现在开始记录一下每天的学习情况.主力LOJ? 2019/9/5 LibreOJ #2543. 「JXOI2018」排序问题 答案显然是\(\frac{(n+m)!}{Cnt_1!Cnt_2!\cdo ...

最新文章

  1. js获取当前Frame在父页面中的id
  2. linux开始时间and结束时间,Linux NTP configure and Hangcheck-time
  3. 这不应该是19岁女孩的结局,这不应该是围观者该有的表达!
  4. mysql explain字段含义_史上最全的explain常见结果含义分析,值得收藏
  5. 大型Java项目架构演进(小白)
  6. java test20006_Java单例7种测试实践
  7. UVA12657 Boxes in a Line【模拟】
  8. [转载] 聚类算法总结
  9. 小程序授权登录,后台发送链接,得到参数。
  10. FREETEXTBOX
  11. Activiti7 + Spring Boot + mybatis Plus + Oracle 数据库整合-学习篇(一)
  12. win10桌面背景为什么突然变黑了 win10桌面背景不显示解决方法
  13. linux系统tfs安装,Jenkins使用TFS部署
  14. 蓝桥杯 算法训练 学做菜
  15. 云原生|kubernetes|etcd集群详细介绍+安装部署+调优
  16. iOS 解决报错 Module file /Users/anmo/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/3FOJ1MTM...
  17. List<Map,Object>>怎样取出map集合中的某一个的key值?
  18. 主板是2011针服务器型号,华硕服务器主板 Z9PA-D8/C 双路2011针脚
  19. [转载]屏蔽双显卡笔记本的独显
  20. Oracle - 索引

热门文章

  1. matlab作业1参考答案,matlab课后习题答案1到6章
  2. 与ln的指数转化公式_高考数学48条秒杀型公式与方法
  3. android 获取当前画布,Android硬件位图填坑之获取硬件画布
  4. linux raw设备格式化,SUSE Linux 10配置裸设备(raw devices)
  5. .md是什么文件_Element-UI源码阅读之md显示到页面
  6. _云计算学习路线图素材课件,Linux中软件安装的方式
  7. vue 调用mutation方法_Vuex白话教程第三讲:Vuex旗下的Mutation
  8. leetcode剑指 Offer 29. 顺时针打印矩阵
  9. 你可能没有听说过 js中的 DOM操作还有这个: HTMLCollection 和 NodeList
  10. 计算机一级文档题,计算机一级模拟题