1. 程式人生 > >CF911F Tree Destruction

CF911F Tree Destruction

oid printf tween tex 簡單的 art pri nta leaves

題意翻譯

給你一棵樹,每次挑選這棵樹的兩個葉子,加上他們之間的邊數(距離),然後將其中一個點去掉,問你邊數(距離)之和最大可以是多少.

題目描述

You are given an unweighted tree with n n n vertices. Then n−1 n-1 n1 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 n1 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<=2105 ) — the number of vertices in the tree.

Next n−1 n-1 n1 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 n1 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 }

CF911F Tree Destruction