3206: [Apio2013]道路费用


Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 536  Solved: 252
[Submit][Status][Discuss]

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


Sample Output



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)将没有任何收入。

Source


分析:


一开始有K条特殊边。我们可以二进制枚举哪些选哪些不选。

先把这K条特殊边权值赋-inf跑最小生成树,除了k条边以外其他边肯定在任何枚举中都会选。

那么把那些边缩点,最后剩下k个点。

我们再找出这k个点中可能选的边,最多k^2条。

这样二进制枚举加每次做最小生成树代价是2^k *(k ^ 2)

再dfs一编新树,把没有选的边u - v的路径上所以点暴力取最小值,这样每个点取得最小值记录为mx[i]。

每个点子树内权值和记录为w[i]

记录每个特殊边深度深的点为x

最终答案为∑mx[x] * w[x]。

AC代码:


# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + ;
const int M = 4e5 + ;
const LL inf = 1e18;
int n,m,K,dt,bac[N],base[N],cnt,tot,fa[N];
LL s[N],S[N],mx[N],w[N],ans;int head[N],dep[N],rt;
struct Base{
int fa[N];
void init(int x){for(int i = ;i <= x;i++)fa[i] = i;}
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
}p,q;
struct E{
int u,v;LL w;
void read(bool f){scanf("%d %d",&u,&v);if(f)scanf("%lld",&w);}
}a[M],b[],e[];
struct Edge{
int to,nex;
}edge[N];
void AddEdge(int u,int v)
{
edge[++tot] = (Edge){v,head[u]};
head[u] = tot;
edge[++tot] = (Edge){u,head[v]};
head[v] = tot;
}
bool cmp(E a,E b){return a.w < b.w;}
void dfs(int u)
{
w[u] = s[u];
for(int i = head[u];i;i = edge[i].nex)
{
if(edge[i].to == fa[u])continue;
fa[edge[i].to] = u;
dep[edge[i].to] = dep[u] + ;
dfs(edge[i].to);
w[u] += w[edge[i].to];
}
}
void solve(int sa)
{
tot = ;
for(int i = ;i <= dt;i++)
{
mx[base[i]] = inf;fa[base[i]] = head[base[i]] = ;
p.fa[base[i]] = base[i];
}
for(int i = ;i < K;i++)if(sa >> i & )
{
int x = p.find(b[i].u),y = p.find(b[i].v);
if(x == y)return;
p.fa[y] = x;AddEdge(b[i].u,b[i].v);
}
for(int i = ;i < cnt;i++)
{
int x = p.find(e[i].u),y = p.find(e[i].v);
if(x != y)p.fa[y] = x,AddEdge(e[i].u,e[i].v);
}
dfs(rt);
for(int i = ;i < cnt;i++)
{
int x = e[i].u,y = e[i].v;
if(dep[x] < dep[y])swap(x,y);
while(dep[x] != dep[y])
{
mx[x] = min(mx[x],e[i].w);
x = fa[x];
}
while(x != y)
{
mx[x] = min(mx[x],e[i].w);
mx[y] = min(mx[y],e[i].w);
x = fa[x];y = fa[y];
}
}
LL ret = ;
for(int i = ;i < K;i++)if(sa >> i & )
{
int x = b[i].u,y = b[i].v;
if(dep[x] < dep[y])swap(x,y);
ret += mx[x] * w[x];
}
ans = max(ans,ret);
}
int main()
{
freopen("TOLL.in","r",stdin);
freopen("TOLL.out","w",stdout);
scanf("%d %d %d",&n,&m,&K);
p.init(n);q.init(n);
for(int i = ;i < m;i++)a[i].read();
for(int i = ;i < K;i++)b[i].read();
for(int i = ;i <= n;i++)scanf("%lld",S + i);
sort(a,a + m,cmp);
for(int i = ;i < K;i++)
{
int x = p.find(b[i].u),y = p.find(b[i].v);
if(x != y)p.fa[y] = x;
}
for(int i = ;i < m;i++)
{
int x = p.find(a[i].u),y = p.find(a[i].v);
if(x != y)
{
p.fa[y] = x;
x = q.find(a[i].u),y = q.find(a[i].v);
q.fa[y] = x;
}
}
for(int i = ;i <= n;i++)if(q.find(i) == i)base[++dt] = i,bac[i] = i;
for(int i = ;i <= n;i++)bac[i] = bac[q.find(i)],s[bac[i]] += S[i];
rt = bac[];
for(int i = ;i < m;i++)a[i].u = bac[a[i].u],a[i].v = bac[a[i].v];
for(int i = ;i < K;i++)b[i].u = bac[b[i].u],b[i].v = bac[b[i].v];
for(int i = ;i < m;i++)
{
int x = q.find(a[i].u),y = q.find(a[i].v);
if(x != y)
{
q.fa[y] = x;
e[cnt++] = a[i];
}
}
int all = << K;
for(int i = ;i < all;i++)solve(i);
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return ;
}

[Bzoj3206][Apio2013]道路费用(kruscal)(缩点)的更多相关文章

  1. [BZOJ3206][APIO2013]道路费用(最小生成树)

    3206: [Apio2013]道路费用 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 568  Solved: 266[Submit][Status ...

  2. BZOJ3206 [Apio2013]道路费用

    首先我们强制要求几条待定价的边在MST中,建出MST 我们发现这个MST中原来的边是一定要被选上的,所以可以把点缩起来,搞成一棵只有$K$个点的树 然后$2^K$枚举每条边在不在最终的MST中,让在最 ...

  3. 洛谷P3639 [APIO2013] 道路费用 [生成树的特殊算法]

    题目传送门 道路费用 格式难调,题面就不放了. 分析: 这是一道要细(yan)心(jing)的生成树的好(gui)题. 首先我们看到$k$的范围非常小,那么我们就可以直接$2^k$枚举每一条加边是否选 ...

  4. [APIO2013]道路费用

    题目描述 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人从城镇 1 出发,经过这 ...

  5. 题解 [APIO2013]道路费用

    link Description 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人 ...

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

    参考:http://hzwer.com/6888.html 把k条道路权值设为0,和其他边一起跑MST,然后把此时选中的其他边设为必选,在新图中加上必选变缩成k个点,把所有边重标号,枚举k跳边的选取情 ...

  7. 题解 洛谷 P3639 【[APIO2013]道路费用 】

    不难想到可以\(2^k\)去枚举\(k\)条新边的选择方案,然后加入原图中的边来使图连通,用当前方案的收益去更新答案,但是这样复杂度过不去. 可以先把\(k\)条新边都连上,然后再加入边权从小到大排序 ...

  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. [APIO2013]

    A.机器人 题目大意:给定一个n*m的地图,有一些障碍物和k个机器人,你每次可以选择一个机器人往任意一个方向推,遇到转向器会转向,两个编号相邻的机器人可以合并,求最少推多少次可以全部合并. $n,m\ ...

随机推荐

  1. Fortran学习笔记5(数组Array)

    数组的声明方式 一维数组 二维数组 多维数组 数组索引值的改变 自定义类型的数组定义 对数组内容的设置 利用隐含式循环设置数组初值 对整个数组操作 对部分数组的操作 where函数 Forall函数 ...

  2. 【搜索 技巧】Letter gaps

    需要一定技巧的搜索题 题目描述 记得做过这样一道题 Ponder This Challenge: In the string CABACB, each letter appears exactly t ...

  3. Django 模版语法 三

    使用自定义simple_tag 在 app01 下面创建 templatetags 文件夹,在创建 my_tag.py 文件,内容如下: from django import template fro ...

  4. Lex与Yacc学习(十)之Yacc库

    Yacc库 每个实现都需要有用的例程库,在UNIX系统中,可以通过cc命令行尾端给出-ly标志(或通过其他系统下的等价物)来包含库. 库的内容在不同的实现之间是不同的,但总是包括main()和yyer ...

  5. Python开发:面向对象

    Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的. 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在 ...

  6. 面试准备——rpc面试题

    https://www.jianshu.com/p/28e48e5f9c73 1 什么是 RPC ? RPC (Remote Procedure Call)即远程过程调用,是分布式系统常见的一种通信方 ...

  7. [uiautomator篇] 设置@test的执行顺序

    http://jackyrong.iteye.com/blog/2025609 Brief Junit 4.11里增加了指定测试方法执行顺序的特性 测试类的执行顺序可通过对测试类添加注解 “@FixM ...

  8. 九度oj 题目1342:寻找最长合法括号序列II

    题目描述: 假如给你一个由’(‘和’)’组成的一个随机的括号序列,当然,这个括号序列肯定不能保证是左右括号匹配的,所以给你的任务便是去掉其中的一些括号,使得剩下的括号序列能够左右括号匹配且长度最长,即 ...

  9. LINUX远程强制重启/proc/sys/kernel/sysrq /proc/sysrq-trigger

    1.     # echo 1 > /proc/sys/kernel/sysrq 2.     # echo b > /proc/sysrq-trigger 1. /proc/sys/ke ...

  10. UITableView滑动动画+FPSLabel

    主要使用了tableView的代理方法 行将要显示的时候 - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableView ...