cf 911F 树的直径+贪心
$des$
给定一棵 n 个节点的树,你可以进行 n ? 1 次操作,每次操作步骤如下:
选择 u,v 两个度数为 1 的节点。
将 u,v 之间的距离加到 ans 上。
将 u 从树上删除。
求一个操作序列使得 ans 最大。
$sol$
先把直径拿出来,将直径外的点一个一个的和直径中的某一个端点配对并删掉。最
后再将直径删掉。这样就是对的。
如果当前直径外已经没有点了,那么显然只能将直径的端点删掉。否则一定不会去
删直径的端点。
因为先删一个直径外的点再删直径端点一定是不劣于先删直径端点再删这个直径外
的点的。
$code$
#include <bits/stdc++.h> using namespace std; #define gc getchar()
inline int read() {
int x = ; char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' && c <= '') x = x * + c - '', c = gc;
return x; } #define LL long long
#define Rep(i, a, b) for(int i = a; i <= b; i ++)
#define E exit(0) const int N = 2e5 + ; int disa[N], disb[N], fa[N], A[N], topp[N], size[N], son[N], deep[N], sonjs[N];
bool Be_calc[N], vis[N], is_chain[N];
int Cut[N], js; struct Node {int v, nxt;} G[N << ];
int head[N], cnt; int n, One, Tow; void Link(int u, int v) {
G[++ cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt;
} int Bfs(int start, int dis[]) {
queue <int> Q;
memset(vis, , sizeof vis);
dis[start] = ;
vis[start] = ;
Q.push(start);
while(!Q.empty()) {
int topp = Q.front();
Q.pop();
for(int i = head[topp]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(!vis[v]) {
dis[v] = dis[topp] + ;
vis[v] = ;
Q.push(v);
}
}
}
int ret, retdis = -;
Rep(i, , n) if(dis[i] > retdis) ret = i, retdis = dis[i];
return ret;
} void Dfs1(int u, int f_, int dep) {
fa[u] = f_, deep[u] = dep; size[u] = ;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v == f_) continue;
sonjs[u] ++;
Dfs1(v, u, dep + );
size[u] += size[v];
if(size[v] > size[son[u]]) son[u] = v;
}
} void Dfs2(int u, int tp) {
topp[u] = tp;
if(!son[u]) {
Cut[++ js] = u;
return ;
}
Dfs2(son[u], tp);
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u] && v != son[u]) Dfs2(v, v);
}
} inline int Lca(int x, int y) {
int tpx = topp[x], tpy = topp[y];
while(tpx != tpy) {
if(deep[tpx] < deep[tpy]) swap(x, y), swap(tpx, tpy);
x = fa[tpx], tpx = topp[x];
}
if(deep[x] < deep[y]) swap(x, y);
return y;
} void Find_chain() {
int lca = Lca(One,Tow);
int tmp1 = One, tmp2 = Tow;
while(tmp1 != lca) {
is_chain[tmp1] = ;
tmp1 = fa[tmp1];
}
while(tmp2 != lca) {
is_chain[tmp2] = ;
tmp2 = fa[tmp2];
}
is_chain[lca] = ;
} int o_1[N], o_2[N], o_3[N], tot; int main() {
n = read();
Rep(i, , n) head[i] = -;
Rep(i, , n - ) {
int u = read(), v = read(); Link(u, v), Link(v, u);
} One = Bfs(, disa);
Tow = Bfs(One, disa);
Bfs(Tow, disb);
Dfs1(One, , );
Dfs2(One, One);
Find_chain(); LL Answer = ;
Rep(i, , js) {
if(is_chain[Cut[i]] || Be_calc[Cut[i]]) continue;
int now = Cut[i]; while(!Be_calc[now] && !is_chain[now] && !sonjs[now]) {
if(disa[now] > disb[now]) {
o_1[++ tot] = One, o_2[tot] = now, o_3[tot] = now;
Answer += disa[now];
} else {
o_1[++ tot] = Tow, o_2[tot] = now, o_3[tot] = now;
Answer += disb[now];
}
Be_calc[now] = ;
now = fa[now];
sonjs[now] --;
}
} int lca = Lca(One, Tow); while(One != lca) {
o_1[++ tot] = One, o_2[tot] = Tow, o_3[tot] = One;
Answer += disb[One];
One = fa[One];
}
while(Tow != lca) {
o_1[++ tot] = Tow, o_2[tot] = lca, o_3[tot] = Tow;
Answer += (deep[Tow] - deep[lca]);
Tow = fa[Tow];
} cout << Answer << "\n";
Rep(i, , tot) {
cout << o_1[i] << " " << o_2[i] << " " << o_3[i] << "\n";
}
return ;
}
cf 911F 树的直径+贪心的更多相关文章
- Sonya and Ice Cream CodeForces - 1004E 树的直径, 贪心
题目链接 set维护最小值贪心, 刚开始用树的直径+单调队列没调出来... #include <iostream>#include <cstdio> #include < ...
- [TJOI2017] 城市 (树的直径,贪心)
题目链接 Solution 这道题,调了我一晚上... 一直80分 >_<|| ... 考虑到几点: 分开任意一条边 \(u\) ,那么其肯定会断成两棵树. 肯定是分开直径上的边最优,否则 ...
- [SDOI2013]直径 (树的直径,贪心)
题目链接 Solution 我们直接找到一条直径 \(s\),起点为 \(begin\),终点为 \(end\). 从前往后遍历点 \(u\) ,若子树中最大的距离与 \(dis(u,begin)\) ...
- CF911F Tree Destruction (树的直径,贪心)
题目链接 Solution 1.先找出树的直径. 2.遍历直径沿途的每一个节点以及它的子树. 3.然后对于每个非直径节点直接统计答案,令直径的两个端点为 \(x_1,x_2\) . \[Ans=\su ...
- [NOI2003]逃学的小孩 (贪心+树的直径+暴力枚举)
Input 第一行是两个整数N(3 <= N <= 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1<=Ui ...
- CF 120F Spider 树的直径 简单题
一个男孩有n只玩具蜘蛛,每只蜘蛛都是一个树的结构,现在男孩准备把这n只小蜘蛛通过粘贴节点接在一起,形成一只大的蜘蛛.大的蜘蛛也依然是树的结构.输出大的蜘蛛的直径. 知识: 树的直径是指树上的最长简单路 ...
- 【Cf #292 D】Drazil and Morning Exercise(树的直径,树上差分)
有一个经典的问题存在于这个子问题里,就是求出每个点到其他点的最远距离. 这个问题和树的直径有很大的关系,因为事实上距离每个点最远的点一定是直径的两个端点.所以我们可以很容易地进行$3$遍$Dfs$就可 ...
- 牡丹江.2014B(图论,树的直径)
B - Building Fire Stations Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%lld & ...
- 与图论的邂逅01:树的直径&基环树&单调队列
树的直径 定义:树中最远的两个节点之间的距离被称为树的直径. 怎么求呢?有两种官方的算法(不要问官方指谁我也不晓得): 1.两次搜索.首先任选一个点,从它开始搜索,找到离它最远的节点x.然后从x开始 ...
随机推荐
- 摘要 - Digest
首先从md5说起,一般新进入开发行业最先接触的就是md5了,md5本质上是一个hash(谐音:哈希)算法,可以从一个大文件信息中提取出一小段信息,叫提取摘要,有的地方也有提取指纹这种说法,其实指纹这个 ...
- Python之TensorFlow的数据的读取与存储-2
一.我们都知道Python由于GIL的原因导致多线程并不是真正意义上的多线程.但是TensorFlow在做多线程使用的时候是吧GIL锁放开了的.所以TensorFlow是真正意义上的多线程.这里我们主 ...
- NEST 多IndexType与分页
/// <summary> /// POST /_all/employee/_search?typed_keys=true /// </summary> public void ...
- Python 实现自动导入缺失的库
原文:由浅入深:Python 中如何实现自动导入缺失的库? 作者:豌豆花下猫 在写 Python 项目的时候,我们可能经常会遇到导入模块失败的错误:ImportError: No module nam ...
- Python绘制拓扑图(无向图)、有向图、多重图。最短路径计算
前言: 数学中,“图论”研究的是定点和边组成的图形. 计算机中,“网络拓扑”是数学概念中“图”的一个子集.因此,计算机网络拓扑图也可以由节点(即顶点)和链路(即边)来进行定义和绘制. 延伸: 无向图 ...
- 【sqoop】安装配置测试sqoop1
3.1.1 下载sqoop1:sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz 3.1.2 解压并查看目录: [hadoop@hadoop01 ~]$ tar -zxvf sq ...
- p3.BTC-协议
数字货币是文件,难伪造,但是容易复制,不像实体货币,花出去就没了,数字货币存在double spending attack,双花攻击. 去中心化的货币,需要解决两个问题: 1.货币的发行 挖矿 2.交 ...
- Vue.js源码中大量采用的ES6新特性介绍:模块、let、const
1 关于ES6 ECMAScript6(以下简称ES6)是JavaScript语言的最新一代标准,发布于2015年6月,因为ECMA委员会决定从ES6起每年更新一次标准,因此ES6被改名为E ...
- 【转】三个重复的ACK意味着发生拥塞?
三次重复的ACK,可能是丢包引起的,丢包可能是网络拥塞造成的,也可能是信号失真造成的. 三次重复的ACK,也有可能是乱序引起的,而乱序和网络拥塞没有直接关系. 如果就写这两行,感觉什么都没写,接下来的 ...
- Python_模块的定义与使用
1.模块的定义: 1.1 标准格式: import 模块名 模块名.函数名(实参列表) 1.2 特殊格式: from 模块名 import 函数名1,函数名2... 函数名(实参列表) 2.模块的使用 ...