Celeste,啟動!
稍作思考就會發現這題其實很簡單,樹上路徑一眼考慮點分治
對於分治中心,很容易預先求出所有未處理的點到它的距離(模意義下),可以用這些資訊來更新中心的答案
考慮剩下的某個未處理的點 \(x\),它的答案可能由 \(x\) 到分治中心的距離 \(dis_x\),拼上分治中心到另一個點 \(y\) 的距離 \(dis_y\) 構成
由於 \(dis_x\) 是已知的定值,且 \(dis_x,dis_y\in[0,mod)\),因此不難發現只要根據它們的和要取模/不取模兩種情況討論即可:
- 若 \(dis_x+dis_y\) 不取模,則找到最大的 \(dis_y\) 滿足 \(dis_y\le mod-1-dis_x\),用 \(dis_x+dis_y\) 更新答案
- 若 \(dis_x+dis_y\) 取模,則直接找到最大的 \(dis_y\),用 \(dis_x+dis_y\) 對 \(mod\) 取模的值更新答案
用 multiset
維護一下,同時注意 \(dis_x\) 與 \(dis_y\) 不能來自同一子樹這一老生常談的問題即可
總複雜度 \(O(n\log^2 n)\)
#include<cstdio>
#include<iostream>
#include<set>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=100005,INF=1e9;
int n,mod,x,y,z,ans[N],dis[N]; vector <pi> v[N]; multiset <int> s;
namespace Point_Divide
{
int rt,ots,sz[N],mx[N]; bool vis[N];
inline void getrt(CI now=1,CI fa=0)
{
sz[now]=1; mx[now]=0;
for (auto [to,w]:v[now]) if (to!=fa&&!vis[to])
getrt(to,now),sz[now]+=sz[to],mx[now]=max(mx[now],sz[to]);
if (mx[now]=max(mx[now],ots-sz[now]),mx[now]<mx[rt]) rt=now;
}
inline void insert(CI now,CI fa=0)
{
s.insert(dis[now]); for (auto [to,w]:v[now])
if (to!=fa&&!vis[to]) dis[to]=(dis[now]+w)&mod,insert(to,now);
}
inline void remove(CI now,CI fa=0)
{
s.erase(s.find(dis[now])); for (auto [to,w]:v[now])
if (to!=fa&&!vis[to]) dis[to]=(dis[now]+w)&mod,remove(to,now);
}
inline void calc(CI now,CI fa=0)
{
auto it=s.upper_bound(mod-dis[now]);
if (it!=s.begin()) ans[now]=max(ans[now],dis[now]+*(--it));
if (!s.empty()) ans[now]=max(ans[now],(dis[now]+*s.rbegin())&mod);
for (auto [to,w]:v[now]) if (to!=fa&&!vis[to]) calc(to,now);
}
inline void solve(CI now)
{
vis[now]=1; dis[now]=0; insert(now);
ans[now]=max(ans[now],*s.rbegin());
for (auto [to,w]:v[now]) if (!vis[to])
remove(to),calc(to),insert(to); s.clear();
for (auto [to,w]:v[now]) if (!vis[to])
mx[rt=0]=INF,ots=sz[to],getrt(to,now),solve(rt);
}
inline void divide(CI n)
{
mx[rt=0]=INF; ots=n; getrt(); solve(rt);
}
};
using namespace Point_Divide;
int main()
{
scanf("%d%d",&n,&mod); --mod;
for (RI i=1;i<n;++i) scanf("%d%d%d",&x,&y,&z),v[x].push_back(pi(y,z)),v[y].push_back(pi(x,z));
divide(n); for (RI i=1;i<=n;++i) printf("%d\n",ans[i]);
return 0;
}