题目链接  Tree Destructi

题意  给定一棵树,每次可以选定树上的两个叶子,并删去其中的一个。答案每次加上两个选定的叶子之间的距离。

  求最后答案的最大值。

首先求出树的某一条直径,令其端点分别为L, R。

把L看成树的根,那么R一定是叶子结点。

对于那些非直径上的点,离他们最远的点肯定是L或R中的一个(可能也有其他的,但是L或R肯定已经最大了)

所以依次把这些非直径上的点删掉,删掉的时候在L和R中选择一个就行了。

最后把直径删掉即可。

时间复杂度$O(nlogn)$  (应该是可以做到$O(n)$的,但是我比较懒)

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 2e5 + 10; vector <int> v[N]; int n;
int cnt;
int x, y;
int L, R; int f[N][20];
int a[N];
int deep[N], father[N];
int Father[N];
int vis[N];
int c[N];
int isroot[N]; LL ans = 0; queue <int> q; void dfs(int x, int fa, int now){
deep[x] = now;
if (fa){
f[x][0] = fa;
for (int i = 0; f[f[x][i]][i]; ++i)
f[x][i + 1] = f[f[x][i]][i];
} if (now > cnt) cnt = now, L = x;
for (auto u : v[x]){
if (u == fa) continue;
dfs(u, x, now + 1);
}
} void dfs2(int x, int fa, int now){
father[x] = fa;
if (now > cnt) cnt = now, R = x;
for (auto u : v[x]){
if (u == fa) continue;
dfs2(u, x, now + 1);
}
} int LCA(int a, int b){
if (deep[a] < deep[b]) swap(a, b);
for (int i = 0, delta = deep[a] - deep[b]; delta; delta >>= 1, ++i)
if (delta & 1) a = f[a][i]; if (a == b) return a;
dec(i, 19, 0) if (f[a][i] != f[b][i]){
a = f[a][i];
b = f[b][i];
} return f[a][0];
} int dis(int x, int y){
int z = LCA(x, y);
return deep[x] + deep[y] - 2 * deep[z];
} void dfs3(int x, int fa){
vis[x] = 1;
Father[x] = fa;
for (auto u : v[x]){
if (vis[u]) continue;
dfs3(u, x);
++c[x];
}
} int main(){ scanf("%d", &n);
rep(i, 1, n){
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
} L = 0, cnt = 0;
dfs(1, 0, 0); cnt = 0;
R = 0;
memset(father, 0, sizeof father);
dfs2(L, 0, 0); cnt = 0;
x = R;
while (x){
++cnt;
a[cnt] = x;
x = father[x];
} memset(vis, 0, sizeof vis);
rep(i, 1, cnt) vis[a[i]] = 1;
rep(i, 1, n) isroot[i] = vis[i];
rep(i, 1, n) if (!vis[i]){
int now = max(dis(i, L), dis(i, R));
ans += 1ll * now;
} memset(c, 0, sizeof c);
rep(i, 1, cnt) dfs3(a[i], 0);
rep(i, 1, n) if (c[i] == 0 && !isroot[i]) q.push(i); ans = ans + 1ll * cnt * (cnt - 1) / 2;
printf("%lld\n", ans); while (!q.empty()){
x = q.front(); q.pop();
vis[x] = 1;
int al = dis(x, L), ar = dis(x, R);
if (al > ar) printf("%d %d %d\n", L, x, x);
else printf("%d %d %d\n", R, x, x); int u = Father[x];
--c[u];
if (c[u] == 0 && !isroot[u]) q.push(u);
} rep(i, 1, cnt - 1) printf("%d %d %d\n", a[i], a[cnt], a[i]);
return 0;
}

Codeforces 911F Tree Destruction(贪心 && 树的直径)的更多相关文章

  1. Codeforces.911F.Tree Destruction(构造 贪心)

    题目链接 \(Description\) 一棵n个点的树,每次可以选择树上两个叶子节点并删去一个,得到的价值为两点间的距离 删n-1次,问如何能使最后得到的价值最大,并输出方案 \(Solution\ ...

  2. Codeforces 911F Tree Destruction

    Tree Destruction 先把直径扣出来, 然后每个点都和直径的其中一端组合, 这样可以保证是最优的. #include<bits/stdc++.h> #define LL lon ...

  3. [Codeforces 911F] Tree Destruction 解题报告(贪心)

    题目链接: http://codeforces.com/contest/911/problem/F 题目大意: 给你一棵树,每次挑选这棵树的两个度数为1的点,加上他们之间的边数(距离),然后将其中一个 ...

  4. Codeforces 734E Anton and Tree(缩点+树的直径)

    题目链接: Anton and Tree 题意:给出一棵树由0和1构成,一次操作可以将树上一块相同的数字转换为另一个(0->1 , 1->0),求最少几次操作可以把这棵数转化为只有一个数字 ...

  5. Farthest Nodes in a Tree ---LightOj1094(树的直径)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1094 Given a tree (a connected graph with no ...

  6. [NOI2003]逃学的小孩 (贪心+树的直径+暴力枚举)

    Input 第一行是两个整数N(3 <= N <= 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1<=Ui ...

  7. codeforces 14D(搜索+求树的直径模板)

    D. Two Paths time limit per test 2 seconds memory limit per test 64 megabytes input standard input o ...

  8. Codeforces Round #379 (Div. 2) E. Anton and Tree 缩点 树的直径

    传送门 题意: 这道题说的是在一颗有两种颜色的树上,每操作一个节点,可以改变这个节点颜色和相邻同色节点的颜色.问最少操作次数,使得树上颜色相同. 思路: 先缩点,把相同的颜色的相邻节点缩在一起.再求出 ...

  9. codeforces#1187E. Tree Painting(树换根)

    题目链接: http://codeforces.com/contest/1187/problem/E 题意: 给出一颗树,找到一个根节点,使所有节点的子节点数之和最大 数据范围: $2 \le n \ ...

随机推荐

  1. Linux系统软件包之---Apache

    当前互联网主流web服务说明 静态服务: apache 中小型静态web服务的主流,web服务器中的老大哥 nginx 大型新兴网站静态web服务主流,web服务器中的初生牛犊 lighttpd 静态 ...

  2. hdu3366 Count the string

    考虑dp[i]代表前缀s[1...i]出现的次数,必定有dp[nxt[i]] += dp[i] 倒着推就是了 #include <iostream> #include <cstrin ...

  3. C 语言 习题 1-12

    练习 1-12 编写一个程序,以每行一个单词的形式打印其输入. #include <stdio.h> #define IN 1 #define OUT 0 int main(int arg ...

  4. IOS开发学习笔记035-UIScrollView-自动滚动

    让图片自动滚动的话,需要使使用定时器,循环计算当前页的页码.并且在拖动图片时停止计时器,停止拖动时启动计时器. 定时器 方法1: performSelector [self performSelect ...

  5. MySQL != 失效

    字段中包含 NULL 和 其他字符串值时, 字段既包含 NULL 也有字符串类型的值, 使用如下 SQL 无法获取值为 NULL 的部分 SELECT * FROM table_name WHERE ...

  6. 堆STL和重载运算符

    大根堆: 1.priority_queue<int> q;[默认 2. priority_queue< node,vector<node>,less<node> ...

  7. Leetcode 640.求解方程

    求解方程 求解一个给定的方程,将x以字符串"x=#value"的形式返回.该方程仅包含'+',' - '操作,变量 x 和其对应系数. 如果方程没有解,请返回"No so ...

  8. Qt数据库查询之事务操作

    在做借书系统的时候,用到了事务操作,不会使用qt中事务操作怎么写,查了一些博客帖子,并不起作用,后来发现,在进行事务成功判断时,出现问题,正确代码如下 if(QSqlDatabase::databas ...

  9. 一个 Java 的 Socket 服务器和客户端通信的例子

    一个 HelloWord 级别的 Java Socket 通信的例子.通讯过程: 先启动 Server 端,进入一个死循环以便一直监听某端口是否有连接请求.然后运行 Client 端,客户端发出连接请 ...

  10. BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】

    题目 输入格式 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库 的行数 接下来M行的01串,表示标准作文库 接下来N行的01串,表示N篇作文 输出格式 N行,每行一个整数,表示这篇作文的 ...