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开始 ...
随机推荐
- Selenium 配置IE浏览器
1.安装selenium pip install selenium 2.安装IE浏览器driver http://selenium-release.storage.googleapis.com/ind ...
- Linux虚拟机设置静态ip
二.设置静态ip dhclient 动态分配ip 修改 ifcfg-ens33网卡配置文件 静态分配ip dhclient -r (释放动态分配的ip地址) vi /etc/sysconfig/ne ...
- Bootstrap 结合 PHP ,做简单的登录以及注册界面及功能
登录实现 HTML代码 <div class="container"> <?php if (isset($error_msg)): ?> <div c ...
- sql 树形递归查询
sql 树形递归查询: with ProductClass(ClassId,ClassName) as ( union all select c.ClassId,c.ClassName from Cl ...
- Python——Int&Bool
整数类型: int类型,多用于数字运算 print(666) print(6+1) 整数类型转换: v1 = 666 v2 = str(v1) #会得出字符串的666 v1 = True v2 = i ...
- CM的私有仓库搭建
CM的私有仓库搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们有时候会因为网络不稳定的因素,导致安装某些服务直接失败.当安装包比较大的时候,我们就得考虑自建私有仓库 ...
- Mongodb3.6 Replica Set 配置
单机下执行: /usr/local/mongodb/bin/mongod --dbpath /usr/local/mongodb/r1 --port --replSet myset /usr/loca ...
- Jmeter4.0 _Beanshell解析并获取json响应数据数组长度
我们在做jmeter接口测试的时候,有时候碰到开发没返回数据total,只返回了一条条记录,可是呢,我们又需要知道到底返回了多少条数据时,咋办呢?咋办呢?咋办呢? 不要急,接下来,让我们见证奇迹是如何 ...
- ServicePointManager 类
地址:https://docs.microsoft.com/zh-cn/dotnet/api/system.net.servicepointmanager?redirectedfrom=MSDN&am ...
- 请解释下在单线程模型中Message、Handler、MessageQueue、Looper之间的关系
对于面试,每个职场人士都经历过,面试官更看中你对于技术的理解是否透彻,需要知其所以然,而实际工作中看中的工作效率,都是在使用API的角度来完成任务,当在一家公司呆久了有跳槽的想法时,个人的亲身经历就是 ...