bzoj2599:[IOI2011]Race (點分治)
阿新 • • 發佈:2018-12-10
Problem
求權值和等於 的路徑中,邊數的最小值。
Solution
點分治… 用 表示到重心距離為 的最短邊數 那麼 因此每次求答案,再把結果加入 中
注:清零不能 …手動吧…
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 200010
#define M 1000010
#define inf 0x3f3f3f3f
int n,k,root=0,num=0,sumroot=0,ans=inf,mx[N],dsum[N],d[N],sz[N],h[N],tmp[M],vis[N];
struct node{int to,z,next;}mp[N<<1];
inline void insert(int x,int y,int z){
mp[++num].to=y;mp[num].z=z;mp[num].next=h[x];h[x] =num;
mp[++num].to=x;mp[num].z=z;mp[num].next=h[y];h[y]=num;
}
void getroot(int x,int fa){
sz[x]=1;mx[x]=0;
for(int i=h[x];i;i=mp[i].next){
int y=mp[i].to;if(y==fa || vis[y]) continue;
getroot(y,x);sz[x]+=sz[y];mx[x]=max(mx[x],sz[y]);
}
mx[x]=max(mx[x],sumroot-sz[x]);
if(mx[x]<mx[root]) root= x;
}
void calc(int x,int fa){
if(dsum[x]<=k) ans=min(ans,tmp[k-dsum[x]]+d[x]);
for(int i=h[x];i;i=mp[i].next){
int y=mp[i].to;if(y==fa || vis[y]) continue;
dsum[y]=dsum[x]+mp[i].z;d[y]=d[x]+1;
calc(y,x);
}
}
void update(int x,int fa,int t){
if(dsum[x]<=k){
if(t) tmp[dsum[x]]=min(tmp[dsum[x]],d[x]);
else tmp[dsum[x]]=inf;
}
for(int i=h[x];i;i=mp[i].next){
int y=mp[i].to;if(y==fa || vis[y]) continue;
update(y,x,t);
}
}
void solve(int x){
vis[x]=1;tmp[0]=0;
for(int i=h[x];i;i=mp[i].next){
int y=mp[i].to;if(vis[y]) continue;
d[y]=1;dsum[y]=mp[i].z;
calc(y,0);update(y,0,1);
}
for(int i=h[x];i;i=mp[i].next) if(!vis[mp[i].to]) update(mp[i].to,0,0);
for(int i=h[x];i;i=mp[i].next){
int y=mp[i].to;if(vis[y]) continue;
sumroot=sz[y];root=0;getroot(y,0);solve(root);
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
insert(x+1,y+1,z);
}
for(int i=1;i<=k;i++) tmp[i]=inf;
mx[0]=inf;sumroot=n;getroot(1,0);
solve(root);
if(ans==inf) puts("-1");
else printf("%d\n",ans);
return 0;
}