CF911F Tree Destruction

题意翻译

给你一棵树,每次挑选这棵树的两个叶子,加上他们之间的边数(距离),然后将其中一个点去掉,问你边数(距离)之和最大可以是多少.

题目描述

You are given an unweighted tree with n n n vertices. Then n−1 n-1 n−1 following operations are applied to the tree. A single operation consists of the following steps:

  1. choose two leaves;
  2. add the length of the simple path between them to the answer;
  3. remove one of the chosen leaves from the tree.

Initial answer (before applying operations) is 0 0 0 . Obviously after n−1 n-1 n−1 such operations the tree will consist of a single vertex.

Calculate the maximal possible answer you can achieve, and construct a sequence of operations that allows you to achieve this answer!

输入输出格式

输入格式:

The first line contains one integer number n n n ( 2<=n<=2⋅105 2<=n<=2·10^{5} 2<=n<=2⋅105 ) — the number of vertices in the tree.

Next n−1 n-1 n−1 lines describe the edges of the tree in form ai,bi a_{i},b_{i} ai?,bi? ( 1<=ai 1<=a_{i} 1<=ai? , bi<=n b_{i}<=n bi?<=n , ai≠bi a_{i}≠b_{i} ai?≠bi? ). It is guaranteed that given graph is a tree.

输出格式:

In the first line print one integer number — maximal possible answer.

In the next n−1 n-1 n−1 lines print the operations in order of their applying in format ai,bi,ci a_{i},b_{i},c_{i} ai?,bi?,ci? , where ai,bi a_{i},b_{i} ai?,bi? — pair of the leaves that are chosen in the current operation ( 1<=ai 1<=a_{i} 1<=ai? , bi<=n b_{i}<=n bi?<=n ), ci c_{i} ci? ( 1<=ci<=n 1<=c_{i}<=n 1<=ci?<=n , ci=ai c_{i}=a_{i} ci?=ai? or ci=bi c_{i}=b_{i} ci?=bi? ) — choosen leaf that is removed from the tree in the current operation.

See the examples for better understanding.

输入输出样例

输入样例#1:

3
1 2
1 3

输出样例#1:

3
2 3 3
2 1 1

输入样例#2:

5
1 2
1 3
2 4
2 5

输出样例#2:

9
3 5 5
4 3 3
4 1 1
4 2 2

Solution:

  贪心+树的直径。

  dfs处理出树的直径,然后先删去非直径上的分枝的叶子节点,再删直径。

  树的直径一定是树上最长的一条简单路径,然后每次删掉非直径上的叶子节点的最远距离,一定是该节点与直径两端点中的某一个搭配出的最长距离,证明就一句话,不可能存在两个都是非直径上的叶子节点的路径超过直径的长度,画图或者脑补,其实蛮简单的贪心,就是难想到。

  具体实现时,两遍dfs处理出直径,再dfs一遍处理出各节点到直径两端的距离,直径上的节点对答案的总贡献直接等差数列求和,非直径上的点直接累加到直径两段距离的最大值,然后输出方案,我的做法是将非直径上的节点和直径两端点的搭配都压入堆中,以距离为关键字,每次弹出就输出方案,最后只剩直径时就是固定一端依次删另一端就好了。

代码:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
 6 using namespace std;
 7 const int N=4e5+7;
 8 int n,to[N],net[N],h[N],cnt;
 9 int tp[N],q[N],tot,maxn;
10 ll dis1[N],dis2[N],ans;
11 bool vis[N];
12 struct node{
13     int u,v;
14     ll d;
15     node(int a=0,int b=0,ll c=0){u=a;v=b;d=c;}
16     bool operator<(const node &a)const {return d<a.d;}
17 };
18 priority_queue<node>Q;
19
20 il int gi(){
21     int a=0;char x=getchar();
22     while(x<‘0‘||x>‘9‘)x=getchar();
23     while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar();
24     return a;
25 }
26
27 il void add(int u,int v){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;}
28
29 il void dfs1(int u,int lst){
30     for(int i=h[u];i;i=net[i])
31         if(!vis[to[i]]) vis[to[i]]=1,dfs1(to[i],lst+1),vis[to[i]]=0;
32     if(lst>maxn) q[tot=1]=u,maxn=lst;
33 }
34
35 il void dfs2(int u,int lst){
36     for(int i=h[u];i;i=net[i])
37         if(!vis[to[i]]) tp[lst]=to[i],vis[to[i]]=1,dfs2(to[i],lst+1),vis[to[i]]=0;
38     if(lst>tot) {
39         tot=lst;
40         For(i,2,lst) q[i]=tp[i];
41     }
42 }
43
44 il void dfs3(int u,ll *a){
45     for(int i=h[u];i;i=net[i])
46         if(!vis[to[i]]) a[to[i]]=a[u]+1,vis[to[i]]=1,dfs3(to[i],a),vis[to[i]]=0;
47 }
48
49 int main(){
50     n=gi();
51     int u,v;
52     For(i,1,n-1) u=gi(),v=gi(),add(u,v),add(v,u);
53     vis[1]=1,dfs1(1,0),tot=0,vis[1]=0,vis[q[1]]=1,dfs2(q[1],2),tot--;
54     dfs3(q[1],dis1),vis[q[1]]=0,vis[q[tot]]=1,dfs3(q[tot],dis2);
55     For(i,1,tot) vis[q[i]]=1;
56     ans=1ll*tot*(tot-1)/2;
57     For(i,1,n)
58         if(!vis[i])ans+=max(dis1[i],dis2[i]),Q.push(node(q[1],i,dis1[i])),Q.push(node(q[tot],i,dis2[i]));
59     printf("%lld\n",ans);
60     while(!Q.empty()){
61         node a=Q.top();Q.pop();
62         if(!vis[a.v]) printf("%d %d %d\n",a.u,a.v,a.v),vis[a.v]=1;
63     }
64     Bor(i,2,tot) printf("%d %d %d\n",q[1],q[i],q[i]);
65     return 0;
66 }

原文地址:https://www.cnblogs.com/five20/p/9369698.html

时间: 2024-07-31 16:57:47

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

「CF911F」Tree Destruction

传送门 Luogu 解题思路 显然的贪心策略,因为每次都要尽量使得删点后的收益最大. 我们可以求出树的直径(因为树上的任意一个节点与其距离最远的点一定是直径的端点). 然后我们对于所有不是直径上的点,从叶子开始,从下往上删点,最后再由深而浅删掉直径. 最后输出答案即可. 细节注意事项 有些地方的计算不要写错式子之类的 参考代码 #include <algorithm> #include <iostream> #include <cstring> #include <

Codeforces 911F Tree Destruction(贪心 &amp;&amp; 树的直径)

题目链接  Tree Destructi 题意  给定一棵树,每次可以选定树上的两个叶子,并删去其中的一个.答案每次加上两个选定的叶子之间的距离. 求最后答案的最大值. 首先求出树的某一条直径,令其端点分别为L, R. 把L看成树的根,那么R一定是叶子结点. 对于那些非直径上的点,离他们最远的点肯定是L或R中的一个(可能也有其他的,但是L或R肯定已经最大了) 所以依次把这些非直径上的点删掉,删掉的时候在L和R中选择一个就行了. 最后把直径删掉即可. 时间复杂度$O(nlogn)$  (应该是可以

CF.911F.Tree Destruction(构造 贪心)

题目链接 \(Description\) 一棵n个点的树,每次可以选择树上两个叶子节点并删去一个,得到的价值为两点间的距离 删n-1次,问如何能使最后得到的价值最大,并输出方案 \(Solution\) 树上距离,求最大,可以考虑下树的直径 假如已知树的直径u->v,那么任意一点x到达其他点的最远距离就是u,v中一点(如果不是这样,那直径一定可以更长而不是uv) 假设x距u最远,那肯定是删x 删直径上的点(直径端点)会导致一些点取不到最远距离 既然这样按顺序删非直径上的点,最后删直径端点 #in

CodeForces - 963B Destruction of a Tree (dfs+思维题)

B. Destruction of a Tree time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output You are given a tree (a graph with n vertices and n?-?1 edges in which it's possible to reach any vertex from any ot

Codeforces Round #475 (Div. 2) D. Destruction of a Tree

1 You are given a tree (a graph with n vertices and n?-?1 edges in which it's possible to reach any vertex from any other vertex using only its edges). 2 3 A vertex can be destroyed if this vertex has even degree. If you destroy a vertex, all edges c

cf963b Destruction of a Tree

越靠近叶子越优先删掉 #include <iostream> #include <vector> #include <cstdio> using namespace std; int n, uu, hea[200005], cnt, deg[200005], fa[200005]; bool vis[200005]; vector<int> shu; vector<int> ans; struct Edge{ int too, nxt; }edg

Codeforces 963B Destruction of a Tree 【贪心】

本题的贪心策略是:每次删除连到叶子结点的dfs链上离根最远的偶数度的结点 greed is good 实现方法是先维护一个degree[i]表示第i个点有多少个度,然后dfs,当每一个结点的所有子节点被访问后准备返回时判断当前结点degree的奇偶性,如果是偶数就删除,是奇数就什么都不做.这样能保证你删除的结点[的子孙]度数都是奇数,及保证删除了[离根最远的偶数度的结点].每次删除要把它父亲和son的degree都减1,并且如果son的degree减完以后是偶数的话就把son也删除.(以为这样能

easyui js取消选中 Tree 指定节点

取消所有选中 var rootNodes = treeObject.tree('getRoots'); for ( var i = 0; i < rootNodes.length; i++) { var node = treeObject.tree('find', rootNodes[i].id); treeObject.tree('uncheck', node.target); }