原题链接:A-LCT
题意:给一颗有根树,依次给出n-1行的信息,分别为a,b,c,意思是链接a和b之后,询问以c为根节点的最大深度。保证询问c的时候,c不会是其他节点的儿子。
思路:先构建出树,然后从根节点跑出每个节点的深度。因为题目保证了询问c的时候,c不会是其他节点的儿子,所以顺序的求出当前联通块的根节点的深度,这个深度就是之后询问这个点的答案。
//冷静,冷静,冷静
//调不出来就重构
#pragma GCC optimize(2)
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=1e6+10,mod=1000000007;
ll fa[N];
ll a[N],b[N],c[N],ans[N];
vector<ll> mp[N];
ll cnt[N];
ll h[N];
ll find(ll x)
{
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll t;cin>>t;
while(t--)
{
ll n;cin>>n;
for(int i=1;i<=n;i++)
{
mp[i].clear();
cnt[i]=0,h[i]=0,fa[i]=i,ans[i]=0;
}
for(int i=1;i<n;i++)
{
cin>>a[i]>>b[i]>>c[i];
mp[a[i]].push_back(b[i]);
cnt[b[i]]++;
}
ll foot=-1;
for(int i=1;i<=n;i++)
{
if(cnt[i]==0)
{
foot=i;
break;
}
}
queue<ll> op;
op.push(foot);
while(op.size())
{
ll v=op.front();op.pop();
for(auto w:mp[v])
{
h[w]=h[v]+1;
op.push(w);
}
}
for(int i=1;i<n;i++)
{
ll x=a[i],y=b[i],z=c[i];
fa[find(y)]=fa[find(x)];//将b合并到a
ans[find(x)]=max(ans[find(y)],ans[y]+h[y]-h[find(x)]);
//如果x是其他点的子节点,那么之后的询问中,x这个节点肯定不会被询问,因为题目保证询问的点肯定不是其他点的子节点,所以只需要更新当前点的祖宗节点就可以了
//ans[y]代表y为根节点的深度,h[y]-h[find(x)]代表y节点于x的祖宗节点的距离,相加就是新的答案
//因为可能存在其他分叉,所以需要和x祖宗节点本身答案进行比较
cout<<ans[z]<<' ';
}
cout<<endl;
}
return 0;
}