题面
题意
给出一棵树,每条边有一个长度,每次询问给出一个L,请选择一个符合要求的最大联通块,要求该联通块中所有点到树上离它最远的点的距离的最大值与最小值之差小于等于L,输出联通块的最大大小。
做法
首先要求出每个点到树上离它最远的点的距离,然后以此距离最短的点为根节点,可以发现此时所有点到最远点必定经过这个根节点,这就意味着该树有着类似笛卡尔树的性质:根节点到最远点的距离是以它为根的子树中最小的,那么对于每个询问只要分别求出每个点子树中与其距离相差L及以内的点一共有几个即可。
对于这个问题可以考虑每个点对其祖先的贡献,用树上倍增+树上差分即可解决,总时间复杂度为O(q*n*logn).
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define lg 18
#define INF 0x3f3f3f3f3f3f3f3f
#define N 100100
using namespace std;
ll n,m,bb,first[N],mx[N][2],d[N],son[N],gen,fa[N][20],cf[N],ans[N];
struct Bn
{
ll to,next,quan;
}bn[N<<1];
inline void add(ll u,ll v,ll w)
{
bb++;
bn[bb].to=v;
bn[bb].quan=w;
bn[bb].next=first[u];
first[u]=bb;
}
void get(ll now,ll last)
{
ll p,q,t;
for(p=first[now];p!=-1;p=bn[p].next)
{
if(bn[p].to==last) continue;
get(bn[p].to,now);
t=mx[bn[p].to][0]+bn[p].quan;
if(t>mx[now][0]) mx[now][1]=mx[now][0],mx[now][0]=t,son[now]=bn[p].to;
else mx[now][1]=max(mx[now][1],t);
}
}
void g2(ll now,ll last,ll sum)
{
ll p,q;
d[now]=max(d[now],mx[now][0]);
for(p=first[now];p!=-1;p=bn[p].next)
{
if(bn[p].to==last) continue;
d[bn[p].to]=max(d[bn[p].to],sum+bn[p].quan);
if(bn[p].to==son[now])
{
d[bn[p].to]=max(d[bn[p].to],mx[now][1]+bn[p].quan);
g2(bn[p].to,now,max(sum,mx[now][1])+bn[p].quan);
}
else
{
d[bn[p].to]=max(d[bn[p].to],mx[now][0]+bn[p].quan);
g2(bn[p].to,now,max(sum,mx[now][0])+bn[p].quan);
}
}
}
void dfs(ll now,ll last)
{
ll p,q;
for(p=first[now];p!=-1;p=bn[p].next)
{
if(bn[p].to==last) continue;
fa[bn[p].to][0]=now;
dfs(bn[p].to,now);
}
}
inline ll find(ll u,ll v)
{
ll i,yu=u;
for(i=lg;i>=0&&u;i--)
{
if(d[yu]-d[fa[u][i]]<=v) u=fa[u][i];
}
return fa[u][0];
}
ll Dfs(ll now,ll last)
{
ll p,q,t=cf[now];
for(p=first[now];p!=-1;p=bn[p].next)
{
if(bn[p].to==last) continue;
t+=Dfs(bn[p].to,now);
}
ans[now]=t;
return t;
}
int main()
{
memset(first,-1,sizeof(first));
ll i,j,p,q,o;
cin>>n;
for(i=1;i<n;i++)
{
scanf("%lld%lld%lld",&p,&q,&o);
add(p,q,o),add(q,p,o);
}
get(1,0);
g2(1,0,0);
p=INF;
for(i=1;i<=n;i++)
{
if(d[i]<p)
{
p=d[i];
gen=i;
}
}
dfs(gen,-1);
for(i=1;i<=lg;i++)
{
for(j=1;j<=n;j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
d[0]=-INF;
cin>>m;
for(i=1;i<=m;i++)
{
memset(ans,0,sizeof(ans));
memset(cf,0,sizeof(cf));
scanf("%lld",&p);
for(j=1;j<=n;j++)
{
q=find(j,p);
cf[j]++,cf[q]--;
}
Dfs(gen,-1);
q=0;
for(j=1;j<=n;j++)
{
q=max(q,ans[j]);
}
printf("%lld\n",q);
}
}