[IOI2011]Race
淀粉质的板子题吧。
考虑处理一颗子树答案时拿其他子树的答案来更新。
具体来说是维护一个桶,记录到分治点距离为\(s\)的点的最短路径。
要记得用队列来清空,不然复杂度挂飞。
Race
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long
ll n,k;
struct P{
ll to,next,v;
}e[400005];
ll cnt,head[400005],ans;
ll siz[400005],dp[400005],sum,rt,minn;
ll minc[1000005];
bool vis[400005];
std::queue<int>QWQ;
inline void add(ll x,ll y,ll z){
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].v = z;
head[x] = cnt;
}
inline void find(ll now,ll fa){
siz[now] = 1;
for(int i = head[now];i;i = e[i].next){
ll v = e[i].to;
if(v == fa || vis[v])
continue;
find(v,now);
siz[now] += siz[v];
}
dp[now] = std::max(siz[now],sum - siz[now]);
// std::cout<<now<<" "<<dp[now]<<std::endl;
if(dp[now] <= minn)
rt = now,minn = dp[now];
}
inline void gotans(ll u,ll s,ll cnt,ll fa){
// std::cout<<u<<" "<<s<<" "<<cnt<<std::endl;
if(s > k)
return ;
ans = std::min(minc[k - s] + cnt,ans);
for(int i = head[u];i;i = e[i].next){
ll v = e[i].to;
if(vis[v] || v == fa)
continue;
gotans(v,s + e[i].v,cnt + 1,u);
}
}
inline void up(ll u,ll s,ll cnt,ll fa){
// std::cout<<u<<std::endl;
if(s > k)
return ;
minc[s] = std::min(minc[s],cnt);
if(minc[s] == cnt)
QWQ.push(s);
for(int i = head[u];i;i = e[i].next){
ll v = e[i].to;
if(vis[v] || v == fa)
continue;
up(v,s + e[i].v,cnt + 1,u);
}
}
inline void divide(ll now){
// std::cout<<now<<" "<<dp[now]<<std::endl;
vis[now] = 1;
for(int i = head[now];i;i = e[i].next){
ll v = e[i].to;
if(vis[v])
continue;
gotans(v,e[i].v,1,now);
up(v,e[i].v,1,now);
}
while(!QWQ.empty()){
minc[QWQ.front()] = 0x3f3f3f3f;
// std::cout<<QWQ.front()<<std::endl;
QWQ.pop();
}
for(int i = head[now];i;i = e[i].next){
ll v = e[i].to;
// std::cout<<v<<std::endl;
if(vis[v])
continue;
sum = minn = siz[v];
// std::cout<<sum<<" "<<minn<<std::endl;
find(v,now);
// std::cout<<":"<<rt<<std::endl;
divide(rt);
}
}
int main(){
std::memset(minc,0x3f,sizeof(minc));
minc[0] = 0;
scanf("%lld%lld",&n,&k);
for(int i = 1;i <= n - 1;++i){
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
sum = minn = n;
ans = 0x3f3f3f3f;
find(0,-1);
divide(rt);
if(ans != 0x3f3f3f3f)
std::cout<<ans<<std::endl;
else
puts("-1");
}