题目的意思:
给出N(n<=50000)个点的一棵树,有M(M<=500)个查询,每个查询限定一个值Q, 求最大连续节点编号的长度,使得从这些点走到的最远距离的最大差不超过Q
先求出每个点的最远到达距离,树直径简单求解方法。
RMQ处理得到的最远距离数组,线性扫描求每个值
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long ll;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define rep(i ,n) for(int i =0 ; i<n; i++)
#define rep1(i ,x , y ) for(int i=x;i<=y;i++)
const int N=200105;
int c[N];
int max_[N][20],min_[N][20],lg2[N]; //20不一定是唯一的。需要计算log(N)/log(2)
void ST(int *a,int n)
{
lg2[0]=-1;
for(int i=1;i<=n;i++)
lg2[i]=lg2[i-1]+(i&(i-1)?0:1);
for(int i=0;i<n;i++) max_[i][0]=a[i]; //a第一个数从零开始
for(int j=1;j<=lg2[n];j++)
for(int i=0;lg2[n-i]>=j;i++)
max_[i][j]=max(max_[i][j-1],max_[i+(1<<(j-1))][j-1]);
for(int i=0;i<n;i++) min_[i][0]=a[i]; //a第一个数从零开始
for(int j=1;j<=lg2[n];j++)
for(int i=0;lg2[n-i]>=j;i++)
min_[i][j]=min(min_[i][j-1],min_[i+(1<<(j-1))][j-1]);
}
int RMQ_Max(int x,int y)
{
int k=lg2[y-x+1];
return max(max_[x][k],max_[y-(1<<k)+1][k]);
}
int RMQ_Min(int x,int y)
{
int k=lg2[y-x+1];
return min(min_[x][k],min_[y-(1<<k)+1][k]);
}
typedef pair<int,int> pii;
vector<pii> G[N];
int dis[2][N], FA , fir , sec;
void dfs(int* d , int u, int fa, int dep){
d[u] = dep;
rep(i , G[u].size()){
if(G[u][i].first != fa){
dfs(d , G[u][i].first, u , dep + G[u][i].second);
}
}
if(d[u] > d[FA]) FA = u;
}
int n,m;
int main()
{
while(scanf("%d %d",&n,&m)==2 && n){
rep1(i , 1 , n) G[i].clear();
rep(i , n - 1){
int u ,v , w;
scanf("%d %d %d",&u,&v,&w);
G[u].push_back(pii(v , w));
G[v].push_back(pii(u , w));
}
FA = 1;
dfs(dis[0] , 1 , -1 , 0);
fir = FA;
dfs(dis[0] , FA , -1 , 0);
sec = FA;
dfs(dis[1] , FA , -1 , 0);
rep1(i , 1 , n){
c[i - 1] = max(dis[1][i] , dis[0][i]);
}
ST(c , n);
while(m--){
int lim ; scanf("%d",&lim);
int l = 0 , max_ = 0;
for(int r = 0 ; r<n ; r++){
while(l < r){
if(RMQ_Max(l , r) - RMQ_Min(l , r) <= lim) break;
l++;
}
max_ = max(max_ , r - l + 1);
}
printf("%d\n",max_);
}
}
return 0;
}