题目的意思:
给出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; }