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开始 ...
随机推荐
- quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0
quartz2.3.0系列目录 官网下载地址:http://www.quartz-scheduler.org/downloads/ 本系列demo全部来源于官网,仅仅是简化和汉化了注释!一部分代码de ...
- C# vb .net实现HSL调整特效滤镜
在.net中,如何简单快捷地实现Photoshop滤镜组中的HSL调整呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第一 ...
- 6.transform?animation?区别?animation-duration【CSS】
1.Transform:它和width.left一样,定义了元素很多静态样式实现变形.旋转.缩放.移位及透视等功能,通过一系列功能的组合我们可以实现很炫酷的静态效果(非动画). 2.Animatio ...
- angular 8 配置路由
一.生成路由文件 按照惯例,有一个独立模块来配置相关路由,这个模块类的名字叫做AppRoutingModule,位于src/app下的app-routing.module.ts文件中. 使用CLI生成 ...
- 在notepad++中编辑时光标消失不见
在notepad++进行编辑时,会不知道的情况下,鼠标光标由竖线变成了下划线,如图 解决方法很简单,是点击”insert“键或者”ins“键,即可改变光标形状.
- Oracle 创建与管理用户
标识用户是 Oracle 数据库管理的基本要求之一,每一个能够连接到数据库的用户都必须是系统的合法用户.用户想要使用 Oracle 的系统资源,就必须拥有相应的权限. 一.身份验证 Oracle 为用 ...
- SAP开源的持续集成-持续交付的解决方案
SAP开源的持续集成/持续交付的解决方案: (1) 一个叫做piper的github项目,包含一个针对Jenkins的共享库和一个方便大家快速搭建CI/CD环境的Docker镜像: (2) 一套SAP ...
- 【mysql】centos7下mysql的安装以及基本操作
centos7使用的MariaDB,替代了早期版本默认的MySQL.MariaDB是MySQL的一个分支,由开源社区维护,采用GPL授权许可,且MariaDB完全贱人MySQL. 检查centos7下 ...
- python(数据精度处理)
一.取整处理 1.int() 向下取整 内置函数 1 n = 3.75 2 print(int(n))>>> 3 3 n = 3.25 4 print(int(n))>> ...
- mongdb插入 查询时间
Robo 3T mongdb客户端 https://www.robomongo.org/ 模糊查找关键字 db.getCollection('test').find({"name" ...