题意:
有一棵带边权的树,共有
n
个节点。有一些蚯蚓需要安置在此树上,每个节点只能安放
给出
数据范围:
2 ≤ n ≤ 105,边权 ≤ 106,q ≤ 50,l ≤ 1e12
样例:
12
5 9 3
2 1 7
11 7 2
6 5 5
2 5 3
6 7 2
1 4 4
8 5 7
1 3 8
11 12 3
10 8 2
10
13 14 14 13 13 4 6 7 2 1
10
10
10
10
10
3
3
5
2
1
题解:
联通块这个条件较为奇怪。对于每一个节点,我们假设它是答案联通块中深度最低之节点,然后只考虑它子树中的节点能否加入此块内,即可简化问题。
我们可以预处理出每个节点与距它最远节点之距离。在第一次dfs时,记录如下信息:
- 每个节点子树中距离它最远之节点。
- 每个节点子树中距离它次远之节点。
在第二次dfs时,我们需要额外传递一个参数
v
,它代表现在访问之节点的父节点向下且不经过该节点可走的最远距离。每次用
现在我们把最远距离最小的节点作为根,重新调整树的父子顺序。然后我们将所有节点按最远距离从大到小排序。每次处理询问时,从前到后遍历排序后的节点序列,使用并查集将它们的子节点合并上去,并在并查集内记录已合并节点个数。最后,使用一个单调前进的指针减掉所有最远距离比该节点最远距离
复杂度 O(nlogn+na(n)).
代码:
#include <bits/stdc++.h>
#define maxn 100010
#define ms(x,y) memset(x,y,sizeof x)
#define inf 0x3f3f3f3f
#define fir first
#define sec second
#define lb(x) (x&(-x))
const int mod=1e9+7;
using namespace std;
typedef long long ll;
typedef pair<ll,int> pi;
int fa[maxn],v[maxn],sz[maxn];
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y){
x=find(x);y=find(y);
if(x==y)return;
if(sz[x]<sz[y]){
fa[x]=y;
sz[y]+=sz[x];
v[y]+=v[x];
}else{
fa[y]=x;
sz[x]+=sz[y];
v[x]+=v[y];
}
}
int n,m;ll l;
struct edge{
int to,dis;
};
vector<edge>graph[maxn];
void addedge(int from,int to,int dis){
graph[from].push_back((edge){to,dis});
}
int q,pa[maxn];ll dp[maxn][2],mx[maxn];
void init(){
for(int i=1;i<=n;i++)fa[i]=i,v[i]=sz[i]=1;
}
void dfs1(int p,int f){
// pa[p]=f;
for(int i=0;i<graph[p].size();i++){
edge e=graph[p][i];if(e.to==f)continue;
dfs1(e.to,p);
if(dp[e.to][1]+e.dis>dp[p][1]){
dp[p][0]=dp[p][1];
dp[p][1]=e.dis+dp[e.to][1];
}else if(dp[e.to][1]+e.dis>dp[p][0]){
dp[p][0]=e.dis+dp[e.to][1];
}
}
}
void dfs2(int p,int f,ll v){
mx[p]=max(dp[p][1],v);//cout<<p<<' '<<mx[p]<<endl;
for(int i=0;i<graph[p].size();i++){
edge e=graph[p][i];if(e.to==f)continue;
if(dp[p][1]==dp[e.to][1]+e.dis){
dfs2(e.to,p,max(v,dp[p][0])+e.dis);
}else{
dfs2(e.to,p,max(v,dp[p][1])+e.dis);
}
}
}
void dfs(int p,int f){
pa[p]=f;
for(int i=0;i<graph[p].size();i++){
edge e=graph[p][i];if(e.to==f)continue;
dfs(e.to,p);
}
}
pi d[maxn];
int main(){
scanf("%d",&n);
for(int i=1,u,v,w;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);addedge(v,u,w);
}
dfs1(1,0);dfs2(1,0,0);
for(int i=1;i<=n;i++)d[i]=make_pair(mx[i],i);
sort(d+1,d+n+1);dfs(d[1].sec,0);
scanf("%d",&q);
while(q--){
scanf("%lld",&l);
init();
int now=n,res=0;
for(int i=n;i;i--){
int p=d[i].sec;
for(int j=0;j<graph[p].size();j++){
if(graph[p][j].to==pa[p])continue;
merge(p,graph[p][j].to);
}
while(d[now].fir-d[i].fir>l)v[find(d[now].sec)]--,now--;
// cout<<p<<' '<<v[find(p)]<<endl;
res=max(res,v[find(p)]);
}
printf("%d\n",res);
}
return 0;
}