1.思路:令根节点为p,对于每条路径,分成经过p的和不经过p的,经过p的通过计算p~p1与p~p2的值来处理,未经过p的递归p的子树处理
递归
void dfs(int x){
vis[x]=true;
get_ans(x);//求出来答案
for(int i=0;i<tu[x].size();i++){
int p=tu[x][i].p;
if(vis[p]) continue;
root=0;
get_root(p,x,sz[p]);//以子树的中心为根递归
dfs(root);
}
}
求出根(子树的重心
void get_root(int x,int fa,int total){
sz[x]=1;
root_ans[x]=0;
for(int i=0;i<tu[x].size();i++){
int p=tu[x][i].p;
int w=tu[x][i].w;
if(p==fa||vis[p]) continue;
get_root(p,x,total);
sz[x]+=sz[p];
root_ans[x]=max(root_ans[x],sz[p]);
}
root_ans[x]=max(root_ans[x],total-sz[x]);
if(!root||root_ans[x]<root_ans[root]){//重心使最大的子树最小
root=x;
}
}
处理经过根节点的答案
void get_d(int x,int fa,int dis,int from){
shu[++tot]=x;
d[x]=dis;
id[x]=from;
for(int i=0;i<tu[x].size();i++){
int p=tu[x][i].p;
int w=tu[x][i].w;
if(vis[p]||p==fa) continue;
get_d(p,x,dis+w,from);
}
}//求处理子树节点到根的距离以及节点所在子树
void get_ans(int x){
tot=0;
shu[++tot]=x;
d[x]=0;
id[x]=x;
for(int i=0;i<tu[x].size();i++){
int p=tu[x][i].p;
int w=tu[x][i].w;
if(vis[p]) continue;
get_d(p,x,w,p);
}
sort(shu+1,shu+tot+1,cmp);
for(int i=1;i<=b;i++){
int l=1,r=tot;
while(l<r&&!ok[i]){//枚举所有出现情况
if(d[shu[l]]+d[shu[r]]>q[i]){//大于目标值,使大的减小
r--;
}else{
if(d[shu[l]]+d[shu[r]]<q[i]){//小于使小的增大
l++;
}else{
if(id[shu[l]]==id[shu[r]]){
if(d[shu[r]]==d[shu[r-1]]) r--;//在一棵子树上的跳过
else l++;
}else{
ok[i]=true;
break;
}
}
}
}
}
}