「CF911F」Tree Destruction

传送门
Luogu

解题思路

显然的贪心策略,因为每次都要尽量使得删点后的收益最大。
我们可以求出树的直径(因为树上的任意一个节点与其距离最远的点一定是直径的端点)。
然后我们对于所有不是直径上的点,从叶子开始,从下往上删点,最后再由深而浅删掉直径。
最后输出答案即可。

细节注意事项

  • 有些地方的计算不要写错式子之类的

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <queue>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= (c == '-'), c = getchar();
    while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    s = f ? -s : s;
}

typedef long long LL;
const int _ = 200010;
const int __ = 400010;

int tot, head[_], nxt[__], ver[__];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; } 

int n, rt, lf, mark[_], fa[_], dep[_];
queue < pair < int, int > > Q;

inline void dfs1(int u, int f) {
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f) continue;
        dep[v] = dep[u] + 1, dfs1(v, u);
    }
}

inline void dfs2(int u, int f) {
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f) continue;
        fa[v] = u, dfs2(v, u), mark[u] |= mark[v];
    }
}

LL ans = 0;

inline void dfs3(int u, int f, int lca) {
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f) continue;
        dfs3(v, u, mark[v] ? v : lca);
    }
    if (!mark[u]) {
        if (dep[u] > dep[u] + dep[lf] - 2 * dep[lca])
            ans += dep[u], Q.push(make_pair(rt, u));
        else
            ans += dep[u] + dep[lf] - 2 * dep[lca], Q.push(make_pair(lf, u));
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
#endif
    read(n);
    for (rg int u, v, i = 1; i < n; ++i)
        read(u), read(v), Add_edge(u, v), Add_edge(v, u);
    dep[1] = 0, dfs1(1, 0);
    rt = 1;
    for (rg int i = 1; i <= n; ++i)
        if (dep[i] > dep[rt]) rt = i;
    dep[rt] = 0, dfs1(rt, 0);
    lf = rt;
    for (rg int i = 1; i <= n; ++i)
        if (dep[i] > dep[lf]) lf = i;
    mark[lf] = 1;
    dfs2(rt, 0);
    dfs3(rt, 0, rt);
    for (rg int i = lf; i != rt; i = fa[i])
        ans += dep[i], Q.push(make_pair(rt, i));
    printf("%lld\n", ans);
    while (!Q.empty()) {
        pair < int, int > x = Q.front(); Q.pop();
        printf("%d %d %d\n", x.first, x.second, x.second);
    }
    return 0;
}

完结撒花 \(qwq\)

原文地址:https://www.cnblogs.com/zsbzsb/p/11745871.html

时间: 2024-10-30 00:50:46

「CF911F」Tree Destruction的相关文章

CF911F Tree Destruction 解题报告

CF911F Tree Destruction 题意翻译 给你一棵树,每次挑选这棵树的两个叶子,加上他们之间的边数(距离),然后将其中一个点去掉,问你边数(距离)之和最大可以是多少. 输入输出格式 输入格式: The first line contains one integer number n \(n\) ( \(2 \le n \le 2 \times 10^{5}\) ) - the number of vertices in the tree. Next \(n-1\) lines d

「SPOJ1487」Query on a tree III

「SPOJ1487」Query on a tree III 传送门 把树的 \(\text{dfs}\) 序抠出来,子树的节点的编号位于一段连续区间,然后直接上建主席树区间第 \(k\) 大即可. 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x"

「SPOJ10707」Count on a tree II

「SPOJ10707」Count on a tree II 传送门 树上莫队板子题. 锻炼基础,没什么好说的. 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w

「luogu2633」Count on a tree

「luogu2633」Count on a tree 传送门 树上主席树板子. 每个节点的根从其父节点更新得到,查询的时候差分一下就好了. 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", s

LibreOJ #2016. 「SCOI2016」美味

二次联通门 : LibreOJ #2016. 「SCOI2016」美味 /* LibreOJ #2016. 「SCOI2016」美味 dalao们都在说这题如果没有加法balabala就可以用可持久化trie解决了 然而我连那个也不会啊QAQ 此题用主席树 从高位到低位贪心 能填1就填1,也就是查询一段区间有没有某个范围的数 (然而由乃dalao说可持久化线段树和可持久化trie是一个东西) */ #include <cstdio> #include <iostream> #inc

「一」创建一个带 ssh 服务的基础镜像(修订版)--使用「docker commit」创建

在介绍如何创建带 ssh 服务的基础镜像之前,我们想回顾一下之前介绍过的内容,其中提到有三种创建镜像的常用办法: 从文件系统导入 从现有容器使用「docker commit」提交 使用 dockerfile 文件 build 本章将主要介绍后面 2 种方法. 步骤如下: $ sudo docker run -ti ubuntu:14.04 /bin/bash #首先,使用我们最熟悉的 「-ti」参数来创建一个容器. [email protected]:/# sshd bash: sshd: co

Loj #3111. 「SDOI2019」染色

Loj #3111. 「SDOI2019」染色 题目描述 给定 \(2 \times n\) 的格点图.其中一些结点有着已知的颜色,其余的结点还没有被染色.一个合法的染色方案不允许相邻结点有相同的染色. 现在一共有 \(c\) 种不同的颜色,依次记为 \(1\) 到 \(c\).请问有多少对未染色结点的合法染色方案? 输入格式 第一行有两个整数 \(n\) 和 \(c\),分别描述了格点图的大小和总的颜色个数. 之后两行,每行有 \(n\) 个整数:如果是 \(0\) 则表示对应结点未被染色,否

「SCOI2012」喵星球上的点名

「SCOI2012」喵星球上的点名 填一个很久以前用 \(\texttt{AC}\) 自动机没填上的坑. 关于本题,能够通过本题的算法很多,这里作者采用的是后缀数组+树状数组的做法. 首先有一个显然的结论:若 \(s_2\) 是 \(s_1\) 的子串,则 \(s_1\) 一定存在一个后缀与 \(s_2\) 的最长公共前缀为 \(|s_2|\). 我们将读入的姓.名.询问串连成一个整体,形成一个字符串 \(s\),且在每一个姓.名.询问串中插入一个不存在文本中的字符,且保证询问串后插入的比姓名串

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]