Squrirrel
Time Limit: 4000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 609 Accepted Submission(s): 186
Problem Description
Master magician `eom` is searching for his naughty squirrel. The squirrel hides at a node of a tree, while its owner `eom` has no idea which node it hides at. As a magician, `eom` can choose a node and release many magical creatures to search his squirrel in all directions at the speed of 1. Besides, he can choose a pair of adjacent nodes on the tree and reduce the distance between them to 0 before releasing magical creatures. Please help him to find the start node to release magical creatures, so that `eom` can find his squirrel in the shortest time even in the worst condition. Note that `eom` is full of wisdom, so that he can optimally make decision to reduce the distance after the start node is determined.
Input
The first line contains a integer T(1≤T≤20), indicating there are T test cases followed.
For each test case, the first line contains one integers n: the number of nodes of the tree(1≤n≤200,000).
In the following n−1 lines, each line has three integers u,v and w, indicating there exists a line between node u and v, which length equals to w(1≤u,v≤n,1≤w≤200).
It is guaranteed that (1≤∑n≤2,000,000).
(1≤T≤20)
(1≤n≤200,000)
(1≤u,v≤n,1≤w≤200)
(1≤∑n≤2000000)
Output
Output two integers. The first one is the index of the start node you should choose and the second one is the least time required in the worst condition. If there are multiple possible ways to choose the start node to minimize the time, the index of start node chosen should be minimum.
Sample Input
1 5 1 5 1 1 2 1 2 3 2 3 4 1
Sample Output
1 2
Source
2019 Multi-University Training Contest 3
Recommend
chendu | We have carefully selected several similar problems for you: 6730 6729 6728 6727 6726
题目大意:给出一根树,问最多使得一条边的边权边为0,问每个点到叶子节点最远距离的最小值。
解题思路:
两边dfs,第一次dfs处理处对于每个点,在他向下的子树中离他第i近的点。并且记录当前点是谁。
以上是不删边得情况。
考虑删边,讲f ,s ,t数组变成二维(原来表示最远点,次远点,和第三远的点)。
变成二维之后表示的含义是 删掉k条边后的x远点。
如何维护
f[u][1]=min(f[fi[u]][0],max(f[fi[u]][1],s[fi[u]][0])+d[fi[u]]);
s[u][1]=min(f[si[u]][0],max(f[si[u]][1],s[si[u]][0])+d[si[u]]);
含义:对于当前u来说,我删掉的边一定是最长路径上的一条边(分两种情况,删掉直接与u相连的并且在最长路径上的,或者在最长路径上的,不与u直接相连的)。
如上图所示分别对应蓝色边和红色边。
但是我们发现,删掉红色边以后 即 f[fi[u]][1]可能不是v到其所有叶子的最远距离 s[v][0]可能大于他。
所以我们要和 s[v][0]取max
f[u][1]=min(f[fi[u]][0],max(f[fi[u]][1],s[fi[u]][0])+d[fi[u]]);
s[u][1]=min(f[si[u]][0],max(f[si[u]][1],s[si[u]][0])+d[si[u]]);
由于我们要的是最远距离的最小值,所以对于两种方案取min
s[u][1]同理。
dfs2的话我们需要维护出 fa[u][i] 即从u节点上边的所有叶子节点到u 删掉i条边得最远距离的最小值。
ans[u]=min(max(max(f[u][1],s[u][0]),fa[u][0]),max(fa[u][1],f[u][0]));
对于当前的ans,我们依旧分两种方案,即删掉 u下面的一条边,或者删掉u上边的一条边。
求得u之后,对于u的子节点v,分三种情况讨论
分别是 v在最长链上,次长链上,第三长链上。
举一个在次长链上的例子:
fa[v][1]=min(fa[v][0]-w,min(max(max(f[u][1],t[u][0]),fa[u][0]),max(fa[u][1],f[u][0]))+w);
分两种情况讨论,删掉u-v这条边,或者不删u-v这条边。
其中不删u-v这条边对应两种情况: 1.删掉u上边的一条边 即fa[u][1]. 2.删掉u最长链上的一条边,即f[u][1]。
其他情况类似。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
struct node
{
int to,nt,w;
}g[N*2];
int tot;
int head[N];
void addedg(int x,int y,int w)
{
tot++;
g[tot].to=y;g[tot].w=w;
g[tot].nt=head[x];head[x]=tot;
}
int f[N][2],s[N][2],t[N][2],fa[N][2];
int fi[N],si[N],ti[N],d[N],ans[N];
void init(int n)
{
tot=0;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++)
{
f[i][0]=f[i][1]=0;
s[i][0]=s[i][1]=0;
t[i][0]=t[i][1]=0;
fa[i][0]=fa[i][1]=0;
fi[i]=si[i]=ti[i]=d[i]=ans[i]=0;
}
}
void dfs1(int u,int fa)
{
for(int i=head[u];i;i=g[i].nt)
{
int to=g[i].to;
if(to==fa)continue;
d[to]=g[i].w;
dfs1(to,u);
if(f[to][0]+d[to]>f[u][0])
{
t[u][0]=s[u][0];
ti[u]=si[u];
s[u][0]=f[u][0];
si[u]=fi[u];
f[u][0]=f[to][0]+d[to];
fi[u]=to;
}
else if(f[to][0]+d[to]>s[u][0])
{
t[u][0]=s[u][0];
ti[u]=si[u];
s[u][0]=f[to][0]+d[to];
si[u]=to;
}
else if(f[to][0]+d[to]>t[u][0])
{
t[u][0]=f[to][0]+d[to];
ti[u]=to;
}
}
f[u][1]=min(f[fi[u]][0],max(f[fi[u]][1],s[fi[u]][0])+d[fi[u]]);
s[u][1]=min(f[si[u]][0],max(f[si[u]][1],s[si[u]][0])+d[si[u]]);
}
void dfs2(int u,int Fa)
{
ans[u]=min(max(max(f[u][1],s[u][0]),fa[u][0]),max(fa[u][1],f[u][0]));
int x=u;
for(int i=head[u];i;i=g[i].nt)
{
int v=g[i].to;
if(v==Fa)continue;
int w=g[i].w;
if(fi[u]==v)
{
fa[v][0]=max(s[x][0],fa[x][0])+w;
fa[v][1]=min(fa[v][0]-w,min(max(fa[u][1],s[u][0]),max(max(s[u][1],t[u][0]),fa[u][0]))+w);
}
else
{
fa[v][0]=max(fa[u][0],f[u][0])+w;
if(si[u]==v) fa[v][1]=min(fa[v][0]-w,min(max(max(f[u][1],t[u][0]),fa[u][0]),max(fa[u][1],f[u][0]))+w);
else fa[v][1]=min(fa[v][0]-w,min(max(max(f[u][1],s[u][0]),fa[u][0]),max(fa[u][1],f[u][0]))+w);
}
dfs2(v,u);
}
}
int main()
{
int _;
cin>>_;
while(_--)
{
int n;
scanf("%d",&n);
init(n);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedg(u,v,w);
addedg(v,u,w);
}
dfs1(1,0);
dfs2(1,0);
int res=0x3f3f3f3f;
int pos;
for(int i=n;i>=1;i--)
{
if(ans[i]<=res)
{
res=ans[i];
pos=i;
}
}
printf("%d %d\n",pos,res);
}
}