洛谷P3639 [APIO2013] 道路费用 [生成树的特殊算法]
道路费用
格式难调,题面就不放了。
分析:
这是一道要细(yan)心(jing)的生成树的好(gui)题。
首先我们看到$k$的范围非常小,那么我们就可以直接$2^k$枚举每一条加边是否选择。然后我们再按权值大小依次加原边并且更新可以影响的加边的权值上限,再树形DP求解。但是这样复杂度是$O(2^k+NM\log M)$,需要考虑优化。
我们能发现,不管加边选不选,有一些边都一定会加入到生成树中,那么我们就把这些边提前连接,然后把产生出的联通块缩点,然后就能形成一个$k+1$个点的新图和$k$条加边和$k$条原边,再用上面的操作就行了。现在的复杂度是$2^k+M\log M$,可以接受了。
细节贼多,贼难调。。。
Code:(代码贼丑。。。)
//It is made by HolseLee on 3rd Oct 2018
//Luogu.org P3639
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std; typedef long long ll;
const int N=1e5+, M=3e5+;
int n,m,K,sta,top,ag[],fa[N],fa2[N];
int mn[N],dep[N],head[N],p[N],cnte;
ll val[N],sum[N],ans;
struct Edge {
int to,nxt;
Edge() {}
Edge(const int _x,const int _y): to(_x),nxt(_y) {}
}edge[M];
struct Node {
int u,v,w;
bool operator < (const Node x) const {
return w < x.w;
}
}e[M],ne[],q[M];
bool mark[M]; inline int read()
{
char ch=getchar(); int num=; bool flag=false;
while( ch<'' || ch>'' ) {
if( ch=='-' ) flag=true; ch=getchar();
}
while( ch>='' && ch<='' ) {
num=num*+ch-''; ch=getchar();
}
return flag ? -num : num;
} int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
int find2(int x) { return fa2[x]==x ? x : fa2[x]=find2(fa2[x]); } inline void add(int x,int y)
{
edge[++cnte]=Edge(y,head[x]); head[x]=cnte;
edge[++cnte]=Edge(x,head[y]); head[y]=cnte;
} void get(int x)
{
sum[x]=val[x];
for(int i=head[x]; i; i=edge[i].nxt) {
if( edge[i].to==fa2[x] ) continue;
dep[edge[i].to]=dep[x]+;
fa2[edge[i].to]=x;
get(edge[i].to);
sum[x]+=sum[edge[i].to];
}
} inline void work()
{
cnte=;
for(int i=; i<=K+; ++i) {
int hl=ag[i]; head[hl]=fa2[hl]=;
fa[hl]=hl;mn[hl]=inf;
}
int u,v,fu,fv;
for(int i=; i<=K; ++i)
if( mark[i] ) {
u=find(ne[i].u), v=find(ne[i].v); if( u==v ) return;
fa[u]=v; add(ne[i].u,ne[i].v);
}
for(int i=; i<=K; ++i) {
u=find(q[i].u), v=find(q[i].v);
if( u!=v ) fa[u]=v, add(q[i].u, q[i].v);
}
get(sta);
for(int i=; i<=K; ++i) {
u=q[i].u, v=q[i].v;
if( dep[u]>dep[v] ) swap(u,v);
while( dep[v]>dep[u] ) mn[v]=min(mn[v],q[i].w), v=fa2[v];
while( u!=v ) {
mn[v]=min(mn[v],q[i].w); mn[u]=min(mn[u],q[i].w);
u=fa2[u], v=fa2[v];
}
}
ll now=;
for(int i=; i<=K; ++i)
if( mark[i] ) {
u=ne[i].u, v=ne[i].v;
if( dep[u]>dep[v] ) swap(u,v);
now+=mn[v]*sum[v];
}
if( ans<now ) ans=now;
} void dfs(int x)
{
if( x>K ) { work(); return; }
mark[x]=; dfs(x+); mark[x]=; dfs(x+);
} int main()
{
n=read(), m=read(), K=read();
for(int i=; i<=m; ++i) {
e[i].u=read(), e[i].v=read(), e[i].w=read();
}
sort(e+,e+m+);
for(int i=; i<=K; ++i) {
ne[i].u=read(), ne[i].v=read();
}
for(int i=; i<=n; ++i) p[i]=read(), fa[i]=fa2[i]=i;
for(int i=; i<=K; ++i) fa[find(ne[i].u)]=find(ne[i].v);
int u,v,fu,fv;
for(int i=; i<=m; ++i) {
u=e[i].u, v=e[i].v;
if( (fu=find(u))!=(fv=find(v)) ) {
fa[fu]=fa[fv]; fa2[find2(u)]=fa2[find2(v)];
}
}
sta=find2();
for(int i=; i<=n; ++i) {
val[fu=find2(i)]+=p[i]; if( fu==i ) ag[++ag[]]=i;
}
for(int i=; i<=K; ++i) {
ne[i].u=find2(ne[i].u); ne[i].v=find2(ne[i].v);
}
for(int i=; i<=m; ++i) {
e[i].u=find2(e[i].u); e[i].v=find2(e[i].v);
}
for(int i=; i<=m; ++i) {
u=find2(e[i].u), v=find2(e[i].v);
if( u!=v ) q[++top]=e[i], fa2[u]=v;
}
dfs(); printf("%lld\n",ans);
return ;
}
洛谷P3639 [APIO2013] 道路费用 [生成树的特殊算法]的更多相关文章
- 洛谷 P5019 铺设道路
题目描述 春春是一名道路工程师,负责铺设一条长度为 \(n\) 的道路. 铺设道路的主要工作是填平下陷的地表.整段道路可以看作是 \(n\) 块首尾相连的区域,一开始,第 \(i\) 块区域下陷的深度 ...
- [BZOJ3206][APIO2013]道路费用(最小生成树)
3206: [Apio2013]道路费用 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 568 Solved: 266[Submit][Status ...
- [Bzoj3206][Apio2013]道路费用(kruscal)(缩点)
3206: [Apio2013]道路费用 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 536 Solved: 252[Submit][Status ...
- 洛谷.4015.运输问题(SPFA费用流)
题目链接 嗯..水题 洛谷这网络流二十四题的难度评价真神奇.. #include <queue> #include <cstdio> #include <cctype&g ...
- 洛谷P4234 最小差值生成树(LCT,生成树)
洛谷题目传送门 和魔法森林有点像,都是动态维护最小生成树(可参考一下Blog的LCT总结相关部分) 至于从小到大还是从大到小当然无所谓啦,我是从小到大排序,每次枚举边,还没连通就连,已连通就替换环上最 ...
- 题解 洛谷 P3639 【[APIO2013]道路费用 】
不难想到可以\(2^k\)去枚举\(k\)条新边的选择方案,然后加入原图中的边来使图连通,用当前方案的收益去更新答案,但是这样复杂度过不去. 可以先把\(k\)条新边都连上,然后再加入边权从小到大排序 ...
- 洛谷P2052 [NOI2011]道路修建(树形DP)
题目描述 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 条双向道路. 每条道 ...
- [APIO2013]道路费用
题目描述 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人从城镇 1 出发,经过这 ...
- 题解 [APIO2013]道路费用
link Description 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人 ...
随机推荐
- cxf开发webservice服务器+客户端(各种类型的参数传递返回)
开发环境:eclipse3.7+jdk1.6.0_29+tomcat6.0.37 XFire搭建webservice: http://www.cnblogs.com/gavinYang/p/35253 ...
- [吴恩达机器学习笔记]12支持向量机2 SVM的正则化参数和决策间距
12.支持向量机 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考资料 斯坦福大学 2014 机器学习教程中文笔记 by 黄海广 12.2 大间距的直观理解- Large Margin I ...
- Vue.js和angular.js区别
Vue.js:易学 简单 指令以v.xxx 一片HTML代码配合json,在new出来Vue,js实例 个人维护项目 适用于移动端 应用超越了angular angular.js:上手难 指令以ng. ...
- 动态规划:LIS优化
对于1D/1D动态规划来说,理论时间复杂度都是O(n^2)的,这种动态规划一般都可以进行优化,贴一篇文章 https://wenku.baidu.com/view/e317b1020740be1e65 ...
- CF544 C 背包 DP
n个人写m行代码,第i人写一行代码有a[i]个bug,问总bug数不超过b的不同方案数. 其实就是个背包,dp[i][j][k]代表前i个人写了j行代码用了k个bug限度,然后随便转移一下就好了 /* ...
- 重构改善既有代码设计--重构手法18:Self Encapsulate Field (自封装字段)
你直接访问一个值域(field),但与值域之间的耦合关系逐渐变得笨拙. 为这个值域建立取值/设值函数(getting/setting methods),并且只以这些函数来访问值域. private i ...
- 【BZOJ】1778: [Usaco2010 Hol]Dotp 驱逐猪猡
[题意]给定无向图,炸弹开始在1,在每个点爆炸概率Q=p/q,不爆炸则等概率往邻点走,求在每个点爆炸的概率.n<=300. [算法]概率+高斯消元 [题解]很直接的会考虑假设每个点爆炸的概率,无 ...
- phpcms取内容发布管理中的来源
调取内容发布管理中的来源,如果直接写{$val['copyfrom']}调取出来的内容为 内容|0 ,要先根据“|”进行拆分,然后再写. 示例: <!--新闻开始--> {pc:co ...
- 爬虫--selenium
什么是selenium? 基本使用 from selenium import webdriver from selenium.webdriver.common.by import By from se ...
- c语言学习笔记.关键字.存储类型关键字等
关键字const 1.修饰变量. 修饰的对象为常量,只读. 2.修饰指针. const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据. const 离变量名近就是用来修 ...