题目描述
一棵具有n个节点的树,每条边(u,v)有一个边权w(u,v)。定义d(i,j)表示离点i第j近的点的距离,且d(i,1)=0。对于每个点i,给你一个Ki,要对每个点求出d(i,Ki)。
点分治
二分转为判定性问题。
提前预处理点分治树方便询问即可。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=10000+10,maxd=15+10,up=10000000;//ji de gai
int h[maxn],go[maxn*2],next[maxn*2],dis[maxn*2],d[maxd][maxn],belong[maxd][maxn],c[maxd][maxn],cc[maxd][maxn];
int tail[maxd],ta[maxd],a[maxn],wz[maxn],zw[maxn],size[maxn],siz[maxn];
bool bz[maxn];
int i,j,k,l,r,mid,t,n,m,ans,tot,top,cnt,now;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int x,int y,int z){
go[++tot]=y;
dis[tot]=z;
next[tot]=h[x];
h[x]=tot;
}
void travel(int x,int y){
a[++top]=x;
int t=h[x];
size[x]=1;
while (t){
if (!bz[go[t]]&&go[t]!=y){
travel(go[t],x);
size[x]+=size[go[t]];
}
t=next[t];
}
}
void dg(int x,int y,int z){
int t=h[x];
while (t){
if (!bz[go[t]]&&go[t]!=y){
d[z][go[t]]=d[z][x]+dis[t];
dg(go[t],x,z);
}
t=next[t];
}
}
bool cmp(int x,int y){
return d[now][x]<d[now][y];
}
void solve(int x,int y){
top=0;
travel(x,0);
int i,j=x,k=0,t;
while (1){
t=h[j];
while (t){
if (!bz[go[t]]&&go[t]!=k&&size[go[t]]>top/2){
k=j;
j=go[t];
break;
}
t=next[t];
}
if (!t) break;
}
fo(i,1,top) belong[y][a[i]]=j;
d[y][j]=0;
dg(j,0,y);
wz[j]=tail[y]+1;
now=y;
sort(a+1,a+top+1,cmp);
fo(i,tail[y]+1,tail[y]+top) c[y][i]=a[i-tail[y]];
tail[y]+=top;
if (y){
zw[j]=ta[y]+1;
now=y-1;
sort(a+1,a+top+1,cmp);
fo(i,ta[y]+1,ta[y]+top) cc[y][i]=a[i-ta[y]];
ta[y]+=top;
}
bz[j]=1;
siz[j]=top;
t=h[j];
while (t){
if (!bz[go[t]]) solve(go[t],y+1);
t=next[t];
}
}
int calc(int x,int v){
int j=0,l,r,mid,t=0;
while (1){
if (j){
l=zw[belong[j][x]]-1;r=l+siz[belong[j][x]];
while (l<r){
mid=(l+r+1)/2;
if (d[j-1][cc[j][mid]]+d[j-1][x]<=v) l=mid;else r=mid-1;
}
t-=l-zw[belong[j][x]]+1;
}
l=wz[belong[j][x]]-1;r=l+siz[belong[j][x]];
while (l<r){
mid=(l+r+1)/2;
if (d[j][c[j][mid]]+d[j][x]<=v) l=mid;else r=mid-1;
}
t+=l-wz[belong[j][x]]+1;
if (belong[j][x]==x) break;
j++;
}
return t;
}
int main(){
freopen("treekth.in","r",stdin);freopen("treekth.out","w",stdout);
n=read();
fo(i,1,n-1){
j=read();k=read();l=read();
add(j,k,l);add(k,j,l);
}
solve(1,0);
fo(i,1,n){
k=read();
l=0;r=up;
while (l<r){
mid=(l+r)/2;
if (calc(i,mid)<k) l=mid+1;else r=mid;
}
printf("%d\n",l);
}
}