参考
题意:
给定n个点的带边权树Q个询问。
下面n-1行给出树
设dp[i]表示树上离 i 点最远点的距离
下面Q行每行一个数字表示询问。
询问L, 表示求出 dp 数组中最长的连续子序列使得序列中最大值-最小值 <= L,输出这个序列的长度。
思路:
求dp数组就是求个树的直径然后dfs一下。
接着就和这题一样了。
对于每个询问,可以用一个单调队列维护一下。O(n)的回答。
5 5 1 2 3 2 3 4 4 5 3 3 4 2 1 2 3 4 5 0 0
1 3 3 3 5
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include <cmath> using namespace std; #define ll long long #define prt(k) ;//cerr<<#k" = "<<k<<endl const int N = 50050; const int M = 2 * N; int n, m; const ll inf = 0x3f3f3f3f; int head[M], to[M], next[M], cost[M]; int tot; void initEdge() { tot = 0; memset(head, -1, sizeof head); } void addEdge(int u, int v, int w) { to[++tot] = v, cost[tot] = w; next[tot] = head[u]; head[u] = tot; } ll dis[N]; int pre[N]; int BFS(int x) ///return farest point from x { memset(dis, -1, sizeof dis); dis[x] = 0; pre[x] = -1; int far = x; queue<int> q; q.push(x); while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];~i;i=next[i]) { int v = to[i]; if(dis[v]==-1) { dis[v] = dis[u] + cost[i]; pre[v] = u; if(dis[far] < dis[v]) far = v; q.push(v); } } } return far; } ll dp[N]; bool vis[N]; void dfs(int u) { vis[u] = true; for(int i=head[u];~i;i=next[i]) { int v = to[i]; if(vis[v]) continue; dp[v] = dp[u] + cost[i]; dfs(v); } } int stk[N]; int len; void build() ///预处理树的直径 { int E = BFS(1); int S = BFS(E); int top = 0; int u = S; len = dis[S]; memset(vis, 0, sizeof vis); while(u != -1) { stk[top++] = u; dp[u] = max(dis[u], len - dis[u]); vis[u] = true; u = pre[u]; } for(int i=0;i<top;i++) dfs(stk[i]); } int qMax[M], qMin[M]; int main() { // freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m)==2, n+m) { initEdge(); for(int i=0;i<n-1;i++) { int u,v,w; scanf("%d%d%d", &u,&v,&w); addEdge(u,v,w); addEdge(v,u,w); } build(); // for(int i=1;i<=n;i++) printf("dp[%d] = %d\n",i,dp[i]); while(m--) { int v; scanf("%d",&v); int ans, hmax, tmax, hmin, tmin; ans=hmax=tmax=hmin=tmin=0; int st = 0; tmax=tmin=-1; for(int i=1;i<=n;i++) { while(hmax<=tmax&&dp[qMax[tmax]]<dp[i]) --tmax; qMax[++tmax] = i; while(hmin<=tmin&&dp[qMin[tmin]]>dp[i]) --tmin; qMin[++tmin] = i; while(dp[qMax[hmax]]-dp[qMin[hmin]] > v) { if(qMax[hmax]<=qMin[hmin]) st = qMax[hmax++]; else st = qMin[hmin++]; } ans=max(ans, i-st); } printf("%d\n", ans); } } }