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开始 ...
随机推荐
- localhost-startStop-1启动失败
背景:在IDEA调试程序的时候,应用起不来,看日志是从main线程切换到localhost-startStop-1线程就开始卡住了 方法一 原因 这个问题和jvm上的熵池策略有关 解决 将$JAVA_ ...
- vmware的三种网络模式讲解
vmware有三种网络设置模式,分别是Bridged(桥接),NAT(网络地址转换),Host-only(私有网络共享主机) 1.Bridged(桥接) 桥接模式默认使用的是:VMnet0 什么是桥接 ...
- power shell导出文件夹目录递归
--获取目录:Get-ChildItem --递归目录:-Recurse --选择想要导出的目录参数,如:文件名,时间,权限等:Select-Object Name, LastWriteTime, M ...
- 服务网关ZuulFilter过滤器--pre/post/error的用法(校验请求信息,获取路由后的请求/响应信息,处理服务网关异常)
微服务中Zuul服务网关一共定义了四种类型的过滤器: pre:在请求被路由(转发)之前调用 route:在路由(请求)转发时被调用 error:服务网关发生异常时被调用 post:在路由(转发)请求后 ...
- 如何通过Restful API的方式读取SAP Commerce Cloud的Product Reference
从SAP官网上找到api的说明: https://api.sap.com/api/commerce_services/resource api endpoint: /rest/v2/electroni ...
- jenkins节点添加
https://blog.csdn.net/bbwangj/article/details/81203381
- oracle命令行导出、导入dmp文件
1.导出语句: exp test/test@127.0.0.1:1521/orcl file=d:\gpmgt.dmp full=n: 导出test用户数据库对象,full=n表示默认只导出test用 ...
- Python——2x和3x的区别汇总
1. 初始解释器编码: 2x:ascii 编码(不自持中文) 3x:unicode编码 推荐全部更换为utf-8 2. 输出方式不同 2x:print ‘你好’2.7版本的两种都支持 3x:print ...
- keekalived+nginx 高可用
高可用环境准备 后端服务器主配置文件 [192.168.2.7-root@web01~]#cat /etc/nginx/nginx.conf user www; worker_processes 1; ...
- Python标准库-datatime和time
Python标准库-datatime和time 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.标准库datatime 1>.datatime模块 #!/usr/bin/e ...