「6月雅礼集训 2017 Day7」电报
【题目大意】
有n个岛屿,第i个岛屿有有向发射站到第$p_i$个岛屿,改变到任意其他岛屿需要花费$c_i$的代价,求使得所有岛屿直接或间接联通的最小代价。
$1 \leq n \leq 10^5, 1 \leq p_i,c_i \leq 10^9$
【题解】
显然最后是个大环,特判原来就是大环的情况。
考虑每个连通块最多保留多少。
树的答案可以直接dp做出来。
环的答案,根据树的答案dp出来。
h[x][0/1]表示当前做到环上第i个点,环是否被切断了,的最大保留价值。
因为环必须被切断一次。所以最后返回h[r.size()][1]即可。
为了方便代码写的是从后向前(不会涉及到初值特判问题)
懒得写tarjan,写的是和昨天”学外语“一样的找环方法。。
# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; const int N = 1e5 + , M = 2e5 + ;
const ll inf = 1e18; vector<int> ring[N]; int rn = ;
int n, p[M], c[M]; int head[N], nxt[M], to[M], tot = , deg[N];
inline void add(int u, int v) {
// cout << u << "-->" << v << endl;
++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
add(u, v), add(v, u);
} namespace SOLVE_RINGS {
struct us {
int fa[N], n;
inline void set(int _n) {
n = _n; for (int i=; i<=n; ++i) fa[i] = i;
}
inline int getf(int x) {
return fa[x] == x ? x : fa[x] = getf(fa[x]);
}
inline void un(int fu, int fv) {
fa[fu] = fv;
}
}U;
bool inrings[N];
int c[N], cn = ;
bool vis[N];
inline void dfs_rings(int x) {
if(vis[x]) {
++rn; for (int i=cn; i; --i) ring[rn].push_back(c[i]);
return ;
}
c[++cn] = x; vis[x] = ;
for (int i=head[x]; i; i=nxt[i]) ++deg[x], dfs_rings(to[i]);
--cn;
} inline void find_rings() {
U.set(n);
for (int i=; i<=n; ++i) {
int fu = U.getf(p[i]), fv = U.getf(i);
if(fu == fv) inrings[i] = ;
else U.un(fu, fv);
}
for (int i=; i<=n; ++i) {
if(!inrings[i]) continue;
cn = ;
dfs_rings(i);
}
} inline void debug_rings() {
for (int i=; i<=rn; ++i) {
printf("num = %d\n ", i);
for (int j=; j<ring[i].size(); ++j)
cout << ring[i][j] << ' ';
cout << endl;
}
} inline void clear_rings() {
for (int i=; i<=rn; ++i) ring[i].clear();
for (int i=; i<=n; ++i) inrings[i] = vis[i] = deg[i] = ;
rn = ;
}
} ll f[N], g[N], h[N][]; inline void dfs_trees(int x, int fa) {
ll mx = ;
for (int i=head[x]; i; i=nxt[i]) {
if(to[i] == fa) continue;
dfs_trees(to[i], x);
mx = max(mx, (ll)c[to[i]]);
f[x] += f[to[i]];
}
g[x] = f[x];
f[x] += mx;
} inline ll solve(vector<int> r) {
ll mx = , s = , res = ;
for (int i=; i<r.size(); ++i) {
int pr = r[(i - + r.size()) % r.size()], nx = r[(i + ) % r.size()];
dfs_trees(r[i], pr);
}
h[r.size()][] = -inf;
h[r.size()][] = ;
for (int i=r.size() - ; ~i; --i) {
int pr = r[(i - + r.size()) % r.size()];
h[i][] = h[i+][] + max(g[r[i]] + c[pr], f[r[i]]);
h[i][] = max(h[i][], h[i+][] + f[r[i]]);
h[i][] = h[i+][] + g[r[i]] + c[pr];
}
return h[][];
} int main() {
// freopen("telegraph.in", "r", stdin);
// freopen("telegraph.out", "w", stdout);
cin >> n;
for (int i=; i<=n; ++i) {
scanf("%d%d", p+i, c+i);
add(p[i], i);
}
SOLVE_RINGS :: find_rings();
if(rn == && ring[rn].size() == n) {
puts("");
return ;
}
// SOLVE_RINGS :: debug_rings();
ll ans = , sum = ;
for (int i=; i<=rn; ++i) ans += solve(ring[i]);
for (int i=; i<=n; ++i) sum += c[i];
cout << sum - ans;
return ;
}
「6月雅礼集训 2017 Day7」电报的更多相关文章
- 「6月雅礼集训 2017 Day7」三明治
[题目大意] $1 \leq n,m \leq 400$ N字形表示:上图第1行第1个那种:Z字形表示上图第1行第2个那种. [题解] 很容易得到结论: 考虑如果紫色比绿色先消去,那么黄色一定会比对应 ...
- 「6月雅礼集训 2017 Day7」回转寿司
[题目大意] 给一个n个数的序列,q次操作,每次选择区间$[l,r]$,给出数p,对于区间$[l,r]$的每个数$x$,做如下操作: 如果$x > p$,就交换$x$和$p$.求每次操作后$p$ ...
- 「6月雅礼集训 2017 Day10」quote
[题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...
- 「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)
原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687 [题目大意] 给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 | ...
- 「6月雅礼集训 2017 Day11」delight
[题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...
- 「6月雅礼集训 2017 Day11」jump
[题目大意] 有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[\max(1, i-x_i), \min(i+x_i, n)]$中. 定义$(i,j)$的距离表示从$i ...
- 「6月雅礼集训 2017 Day11」tree
[题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...
- 「6月雅礼集训 2017 Day10」perm(CodeForces 698F)
[题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多 ...
- 「6月雅礼集训 2017 Day8」route
[题目大意] 给出平面上$n$个点,求一条连接$n$个点的不相交的路径,使得转换的方向符合所给长度为$n-2$的字符串. $n \leq 5000$ [题解] 考虑取凸包上一点,然后如果下一个是‘R' ...
随机推荐
- xml解析----java中4中xml解析方法(转载)
转载:https://www.cnblogs.com/longqingyang/p/5577937.html 描述 XML是一种通用的数据交换格式,它的平台无关性.语言无关性.系统无关性.给数据集成与 ...
- SpringMVC拦截器实现登录认证(转发)
感谢原作者,转发自:http://blog.csdn.net/u014427391/article/details/51419521 以Demo的形式讲诉拦截器的使用 项目结构如图: 需要的jar:有 ...
- iOS-【UIDynamic-UIKit动力学】
如果看不到图片 可以尝试更换浏览器(推荐Safari ) 0.了解 •Dynamic Animator:动画者,为动力学元素提供物理学相关的能力及动画,同时为这些元素提供相关的上下文,是动力学元素与底 ...
- QWidget一生,从创建到销毁事件流
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QWidget一生,从创建到销毁事件流 本文地址:http://techieliang ...
- 【Linux】- mv命令
Linux mv命令用来为文件或目录改名.或将文件或目录移入其它位置. 语法 mv [options] source dest mv [options] source... directory 参数说 ...
- linux的几个发行网站
Red Hat: http://www.redhat.com Fedora: http://fedoraproject.org/ Mandriva: http://www.mandriva ...
- phpcms 最多上传 10 个附件 解决办法
修改文件:/phpcms/libs/classes/form.class.php
- 【python】如何查看已经安装的python软件包和版本
pip 是一个安装和管理 Python 包的工具 , 是 easy_install 的一个替换品. pip freeze可以查看已经安装的python软件包和版本 pip list 也可以
- Stax解析XML示例代码
package org.itat.stax; import java.io.IOException; import java.io.InputStream; import javax.xml.pars ...
- RT-thread 设备驱动组件之IIC总线设备
本文主要介绍RT-thread中IIC总线设备驱动,涉及到的主要文件有:驱动框架文件(i2c_core.c,i2c_dev.c,i2c-bit-ops.c,i2c_dev.h,i2c.h):底层硬件驱 ...