E. Sonya and Ice Cream
题意:
输入
n
,
k
(
1
≤
k
≤
n
≤
1
0
5
)
n,k(1\leq k\leq n\leq 10^5)
n,k(1≤k≤n≤105)
接下来
n
−
1
n-1
n−1行,每行
u
,
v
,
w
u,v,w
u,v,w表示树边;
问在该树上选一条不超过
k
k
k个点的路径,使其它点到该路径最大距离最小。
题解1(树的直径+单调队列):
很容易想到 k k k个点在直径上,然后滑动窗口就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
struct Edge{
int v,w,nxt;
}e[N<<1];
int head[N],cnt;
inline void add(int u,int v,int w){
e[cnt]=(Edge){v,w,head[u]};
head[u]=cnt++;
}
int n,k,mx,s,t;
int f[N],d[N];
void dfs(int u,int fa){
if(d[mx]<d[u])mx=u;f[u]=fa;
for(int i=head[u];~i;i=e[i].nxt){
Edge e1=e[i];
if(e1.v==fa)continue;
d[e1.v]=d[u]+e1.w;
dfs(e1.v,u);
}
}
vector<int>path;
bool vis[N];
int dfs2(int u,int fa){
int mx=0;
for(int i=head[u];~i;i=e[i].nxt){
Edge e1=e[i];
if(e1.v==fa||vis[e1.v])continue;
mx=max(mx,e1.w+dfs2(e1.v,u));
}
return mx;
}
int dis[N];
int ans=1e9;
int q[N],hd,tl;
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
cin>>n>>k;
memset(head,-1,sizeof(head));
for(int i=1,u,v,w;i<n;i++)cin>>u>>v>>w,add(u,v,w),add(v,u,w);
mx=1,dfs(1,0);s=mx;
d[s]=0;dfs(s,0);t=mx;
while(mx)vis[mx]=1,path.push_back(mx),mx=f[mx];
// cout<<s<<" "<<t<<endl;
// for(auto i:path)cout<<i<<" ";cout<<endl;
for(auto i:path)dis[i]=dfs2(i,0);
hd=0;tl=-1;int l;
for(int i=0;i<path.size();i++){
l=max(0,i-k+1);
while(hd<=tl&&i-q[hd]+1>k)hd++;
while(hd<=tl&&dis[path[i]]>=dis[path[q[tl]]])tl--;q[++tl]=i;
ans=min(ans,max(dis[path[q[hd]]],max(d[path[q[tl]]],d[t]-d[path[l]])));
// cout<<ans<<endl;
}
cout<<ans<<endl;
return 0;
}
题解2(逆向思维):
从反方向考虑这个问题,贪心地依次删去叶子节点,直到节点数小于 k k k,叶子节点个数小于等于2,即得到了路径。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int n,k;
#define P pair<int,int>
set<P>g[N],s;
int ans;
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
cin>>n>>k;
for(int i=1,u,v,w;i<n;i++)cin>>u>>v>>w,g[u].insert(P(v,w)),g[v].insert(P(u,w));
for(int i=1;i<=n;i++)if(g[i].size()==1)s.insert(P((*g[i].begin()).second,i));
while(n>k||s.size()>2){
P p1=*s.begin();s.erase(p1);n--;
ans=p1.first;
int v=(*g[p1.second].begin()).first;
g[v].erase(g[v].lower_bound(P(p1.second,0)));
if(g[v].size()==1)s.insert(P((*g[v].begin()).second+ans,v));
}
cout<<ans<<endl;
return 0;
}