(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题意: 传送门
原题目描述在最下面。
简单来说就是给你一颗n个节点的树,然后你自己选择一条长度不超过k个节点的路径(必须是一条树上的路径)。将这条路径看成一个点,问这个点到树上其他点的最远距离最小是多少?
思路:
法一:
首先找到树的一条直径。并且处理处直径起点到其他点的距离。
然后再这个直径上做滑动窗口。滑动窗口的长度不超过k。
然后在O(n)遍历的时候,dfs找出这个点到其他叶子的最远距离,ans和最远距离取min。注意,这个dfs的过程是到其他叶子的最远距离,若碰到直径上的点就return。
法二:
用一个set把所有的叶子存起来,整个树也用set存。叶子按权值排序,树按标号排序(方便删除节点)。
然后维护树上节点数量大于k且叶子数大于2。如果叶子数小于等于2,那图形其实就是一条链。
然后每次选择权值最小的叶子,把它删掉,同时把这个叶子的权值加到它连接的点上去。如果新产生了叶子,则加入叶子set。
最后的答案就是叶子权值中最小的那个。
AC代码:
法一:
#include<bits/stdc++.h>
#define mk make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long LL;
const int inf=2e9+1e8+1234;
const LL linf=8e18+9e17;
const int N = 1e5+7;
const int mod = 998244353;
int n, k, ans;
vector<pair<int, int> >mp[N];
int vis[N], dep[N], dis[N], fa[N];
vector<int> diameter;
void dfs1(int u, int Fa){
if(vis[u])return;
vis[u] = 1;
for(int i = 0; i < mp[u].size(); ++i){
int v = mp[u][i].fi, w = mp[u][i].se;
if(v == Fa)continue;
fa[v] = u;
dis[v] = dis[u] + w;
dfs1(v, u);
}
}
void dfs2(int u, int f){
for(auto x: mp[u]){
if(vis[x.fi] || x.fi == f)continue;
dfs2(x.fi, u);
dep[u] = max(dep[x.fi] + x.se, dep[u]);
}
}
int main(int argc, char const *argv[]){
while(~scanf("%d%d", &n, &k)){
for(int i = 0; i <= n; ++i)mp[i].clear();
diameter.clear();
for(int i = 1, u, v, w; i < n; ++i){
scanf("%d%d%d", &u, &v, &w);
mp[u].pb(mk(v, w));
mp[v].pb(mk(u, w));
}
int st, ed, tmax = -1;
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
dfs1(1, -1);
for(int i = 1; i <= n; ++i){
if(tmax < dis[i]){
tmax = dis[i];
st = i;
}
}
memset(fa, 0, sizeof(fa));
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
dfs1(st, -1);
tmax = -1;
for(int i = 1; i <= n; ++i){
if(tmax < dis[i]){
tmax = dis[i];
ed = i;
}
}
memset(vis, 0, sizeof(vis));
for(int i = ed; i; i = fa[i]){
diameter.push_back(i);
vis[i] = 1;
//printf("%d\n", i);
}
ans = inf;
int h_max = 0, x = 0;
memset(dep, 0, sizeof(dep));
for(int i = 0; i < diameter.size(); ++i, x = 0){
if(i >= k){
x = dis[ed] - dis[diameter[i - k + 1]];
}
x = max(x, dis[diameter[i]]);
dfs2(diameter[i], -1);
h_max = max(h_max, dep[diameter[i]]);
x = max(x, h_max);
ans = min(ans, x);
}
printf("%d\n", ans);
}
return 0;
}
法二:
#include<bits/stdc++.h>
#define mk make_pair
#define pb insert
#define fi first
#define se second
using namespace std;
typedef long long LL;
const int inf=2e9+1e8+1234;
const LL linf=8e18+9e17;
const int N = 4e5+7;
const int mod = 998244353;
set<pair<int, int> >mp[N], st;
int n, k, ans;
int du[N];
int main(int argc, char const *argv[]){
scanf("%d%d", &n, &k);
for(int i = 1, u, v, w; i < n; ++i){
scanf("%d%d%d", &u, &v, &w);
mp[u].pb(mk(v, w));
mp[v].pb(mk(u, w));
du[u]++;du[v]++;
}
for(int i = 1; i <= n; ++i){
if(du[i] == 1){
st.pb(mk((*mp[i].begin()).se, i));
}
}
while(n > k || st.size() > 2){
--n;
ans = (*st.begin()).fi;
int id = (*st.begin()).se;
st.erase(st.begin());
int nex = (*mp[id].begin()).fi;
mp[nex].erase(mp[nex].lower_bound(mk(id, 0)));
if(mp[nex].size() == 1){
st.pb(mk((*mp[nex].begin()).se + ans, nex));
}
}
printf("%d\n", ans);
return 0;
}
/*
10 2
1 2 5
5 7 2
3 2 6
10 6 3
3 8 1
6 4 2
4 1 6
6 9 4
5 2 5
12
*/