Problem - 1822F - Codeforces
两位朋友Alisa和Yuki在他们的花园里种了一棵有n个顶点的树。树是一个无向图,没有循环、回路或多重边。这棵树中的每条边都有一个长度为k。最初,顶点1是树的根。
Alisa和Yuki种植这棵树不仅仅是为了好玩,而是想要卖掉它。该树的成本定义为树上所有顶点中从根到顶点的最大距离。两个顶点u和v之间的距离是沿着从u到v的路径上边的长度之和。
女孩子们学过园艺课程,所以她们知道如何修改树。Alisa和Yuki可以花费c枚硬币将树的根移动到当前根的其中一个邻居。这个操作可以执行任意次数(可能为零)。请注意,树的结构保持不变;唯一的变化是哪个顶点是根。
女孩们想以最大的利润卖出这棵树。利润定义为成本减去操作总成本。利润是树的成本减去操作的总成本。
帮助女孩们,找出通过对树进行任意次数的操作(可能为零)所能获得的最大利润。
输入
第一行包含一个整数t(1≤t≤104)——测试用例的数量。
接下来是每个测试用例的描述。
每个测试用例的第一行包含整数n、k和c(2≤n≤2⋅105;1≤k,c≤109) ——树中顶点的数量,每条边的长度以及操作的成本。
测试用例的下面n−1行包含一对整数ui和vi(1≤ui,vi≤n)——图的边。这些边形成一棵树。
所有测试用例中n的值的总和不超过2×105。
输出
对于每个测试用例,输出一个整数——Yuki和Alisa可以获得的最大利润。
Example
Input
Copy
4
3 2 3
2 1
3 1
5 4 1
2 1
4 2
5 4
3 4
6 5 3
4 1
6 1
2 6
5 1
3 2
10 6 4
1 3
1 9
9 7
7 6
6 4
9 2
2 8
8 5
5 10
Output
Copy
2 12 17 32
题解:
这道题考察树的直径。
树的直径即树中两个最远点之间的路径。
树的直径有一个性质,距离任何一个点最远的点是直径两个端点的其中一个。
通过这个特点,我们可以通过两次DFS求出树的直径的两个端点,
然后分别以这两个端点为根,我们可以求出,每个点距离两个端点的距离,这两个距离之一就是此时距离最远的点的距离
对于代价,我们可以从1节点dfs求得
遍历所有点(此时的最远距离*k - 代价)的最大值即为答案
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
typedef unsigned long long ULL;
const int N = 4e5 + 10;
int mod = 1e9 + 7;
vector<int> p[N];
int n,k,c;
int dep[N];
int cost[N];
int f,ff;
int dep1[N];
void dfs(int u,int fa)
{
for(auto ne:p[u])
{
if(ne == fa)
continue;
cost[ne] = cost[u] + 1;
dfs(ne,u);
}
}
void dfs1(int u,int fa)
{
for(auto ne:p[u])
{
if(ne == fa)
continue;
dep[ne] = dep[u] + 1;
if(dep[ne] > dep[f])
{
f = ne;
}
dfs1(ne,u);
}
}
void dfs2(int u,int fa)
{
for(auto ne:p[u])
{
if(ne == fa)
continue;
dep1[ne] = dep1[u] + 1;
if(dep1[ne] > dep1[ff])
{
ff = ne;
}
dfs2(ne,u);
}
}
void solve()
{
cin >> n >> k >> c;
for(int i = 1;i < n;i++)
{
int l,r;
cin >> l >> r;
p[l].push_back(r);
p[r].push_back(l);
}
cost[1] = 0;
dfs(1,0);
dep[1] = 0;
dfs1(1,0);
dep1[f] = 0;
dfs2(f,0);
dep[ff] = 0;
dfs1(ff,0);
int ans = 0;
for(int i = 1;i <= n;i++)
{
ans = max(max(dep[i],dep1[i])*k - cost[i]*c,ans);
}
cout << ans <<"\n";
for(int i = 1;i <= n;i++)
{
p[i].clear();
dep[i] = 0;
}
}
signed main()
{
ios::sync_with_stdio(0 );
cin.tie(0);cout.tie(0);
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}