题意:
给一颗边带权的数,对于每一个点有
ki
,求从每个点出发第
ki
远的距离。
题解:
点分治。
建出点分树并在每一个节点储存管辖区域的距离,在每一个儿子节点记录对父亲的贡献,查询每一个点时二分,再暴力爬树高验证可行性就好了。
#include<bits/stdc++.h>
using namespace std;
struct io
{
streambuf *ib,*ob;
int buf[50];
inline void init()
{
ios::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
ib=cin.rdbuf();ob=cout.rdbuf();
}
inline int read()
{
char ch=ib->sbumpc();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}
return i*f;
}
inline void W(int x)
{
if(!x){ob->sputc('0');return;}
if(x<0){ob->sputc('-');x=-x;}
while(x)buf[++buf[0]]=x%10,x/=10;
while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}
}
}io;
const int Maxn=1e4+50;
typedef pair<int,int> pii;
int n,k[Maxn],rt,dfn[Maxn],id[Maxn],dis[Maxn],sze[Maxn],vis[Maxn],ind,mx,total,G,lim,Ans[Maxn];
int mn[Maxn*2][18],cnt,Log[Maxn*2],mnpos[Maxn];
int nowfa[Maxn];
vector<pii>edge[Maxn];
vector<int>len[Maxn];
vector<int>LenToFa[Maxn];
inline void dfs(int now,int f,int dist=0)
{
dis[now]=dis[f]+dist;
id[dfn[now]=++ind]=now;
mn[++cnt][0]=dfn[now];
mnpos[now]=cnt;
for(int e=edge[now].size()-1;e>=0;e--)
{
int v=edge[now][e].first,w=edge[now][e].second;
if(v==f)continue;
dfs(v,now,w);
mn[++cnt][0]=dfn[now];
}
}
inline void calcG(int now,int f)
{
sze[now]=1;int nowmx=0;
for(int e=edge[now].size()-1;e>+0;e--)
{
int v=edge[now][e].first;
if(v==f||vis[v])continue;
calcG(v,now);
sze[now]+=sze[v];
nowmx=max(nowmx,sze[v]);
}
nowmx=max(nowmx,total-sze[now]);
if(nowmx<mx)mx=nowmx,G=now;
}
inline void getsze(int now,int f)
{
sze[now]=1;
for(int e=edge[now].size()-1;e>=0;e--)
{
int v=edge[now][e].first;
if(v==f||vis[v])continue;
getsze(v,now);
sze[now]+=sze[v];
}
}
inline void getdep(int fa,int g,int now,int dist,int f)
{
len[fa].push_back(dist);LenToFa[g].push_back(dist);
for(int e=edge[now].size()-1;e>=0;e--)
{
int v=edge[now][e].first,w=edge[now][e].second;
if(vis[v]||v==f)continue;
getdep(fa,g,v,dist+w,now);
}
}
inline void work(int now)
{
vis[now]=1;
len[now].push_back(0);
for(int e=edge[now].size()-1;e>=0;e--)
{
int v=edge[now][e].first,w=edge[now][e].second;
if(vis[v])continue;
getsze(v,now);
total=mx=sze[v];
calcG(v,now);
getdep(now,G,v,w,now);
nowfa[G]=now;
work(G);
}
sort(len[now].begin(),len[now].end());
sort(LenToFa[now].begin(),LenToFa[now].end());
}
inline void SplitTree()
{
mx=total=n;
calcG(1,0);
rt=G;
work(G);
}
inline int getlca(int x,int y)
{
int a=mnpos[x],b=mnpos[y];
if(a>b)swap(a,b);
return id[min(mn[a][Log[b-a]],mn[b-(1<<Log[b-a])+1][Log[b-a]])];
}
inline int getdis(int a,int b)
{
int lca=getlca(a,b);
return dis[a]+dis[b]-2*dis[lca];
}
inline int getans(int x,int length)
{
int last=0,ans=0,now=x;
while(now)
{
int dist=getdis(now,x);
ans+=upper_bound(len[now].begin(),len[now].end(),length-dist)-len[now].begin();
if(last)ans-=upper_bound(LenToFa[last].begin(),LenToFa[last].end(),length-dist)-LenToFa[last].begin();
last=now;
now=nowfa[now];
}
return ans;
}
int main()
{
io.init();
n=io.read();
for(int i=1;i<n;i++)
{
int x=io.read(),y=io.read(),z=io.read();
edge[x].push_back(make_pair(y,z));
edge[y].push_back(make_pair(x,z));
lim+=z;
}
for(int i=1;i<=n;i++)k[i]=io.read();
dfs(1,0);
for(int i=2;i<=cnt;i++)Log[i]=Log[i>>1]+1;
for(int j=1;j<=15;j++)
for(int i=1;i<=cnt&&i+(1<<j)-1<=cnt;i++)
mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
SplitTree();
for(int i=1;i<=n;i++)
{
int l=0,r=lim,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(getans(i,mid)>=k[i])ans=mid,r=mid-1;
else l=mid+1;
}
Ans[i]=ans;
}
for(int i=1;i<=n;i++)io.W(Ans[i]),io.ob->sputc('\n');
}