> 文档中心 > CF911F Tree Destruction(树的直径)

CF911F Tree Destruction(树的直径)

Problem - F - Codeforces

题意:

给一棵树,每次加上两个叶节点距离并删除其中一个叶节点,问最大总距离和是多少。

题解:

叶节点的最大距离肯定是直径两端的距离;那么直径之外的点与其他节点的最远距离肯定在直径的某一端。那么我们首先把直径和其两端点求出来,再加上此节点到那个端点的距离;这个距离可用两个dfs 求直径端点时顺便求出;再考虑直径上的点,每次删掉一端的点就好了,sum+=d[p];

/*keep on going and never give up*/#includeusing namespace std;#define int long long#define LL long long#define fast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);const double E = exp(1);const double PI = acos(-1.0);const int maxn=4e5+10;const int Mod=1e9+7;const int maxn = 2e5+10;struct answer{   int u,v;}a[maxn];vector G[maxn];bool v[maxn];int d[maxn],pre[maxn];int n,tot;int root,leaf;LL ans;void dfs(int u, int fa){    d[u] = d[fa]+1;    pre[u] = fa;//统计距离;    for (int i=0; i<G[u].size(); i++) if (G[u][i]!=fa) dfs(G[u][i],u);} void Find(int x, int df, int dr, bool flag = 1){    for (int i=0; idr) {     a[tot].u = leaf;     a[tot].v = x;     ans += df; } else {     a[tot].u = root;     a[tot].v = x;     ans += dr; } tot++;    }} int main(){    scanf("%d",&n);for (int i=1; i<=n; i++) G[i].clear();tot = 0;int u,v;for (int i=1; i<n; i++) {   scanf("%d %d",&u,&v);   G[u].push_back(v);   G[v].push_back(u);}   ans = 0; d[0] = 0; root = 1; dfs(root,0); for (int i=1; i<=n; i++) if (d[root]<d[i]) root = i; leaf = 1; dfs(root,0);//两遍dfs找到root和leaf; for (int i=1; i<=n; i++) if (d[leaf]<d[i]) leaf = i; memset(v,0,sizeof(v)); int x = leaf; while (1){     v[x] = 1;     Find(x,d[leaf]-d[x],d[x]-1,0);     if (x == root) break;     x = pre[x]; }  x = leaf; while (x!=root) {     a[tot].u = root; a[tot].v = x; tot++;     ans += d[x]-1;     x = pre[x]; }  printf("%I64d\n",ans); for (int i=0; i<tot; i++) printf("%d %d %d\n",a[i].u,a[i].v,a[i].v);}

ps:硬干2400的题真是太有意思了QwQ