HDU 4123 Bob’s Race(树形DP+RMQ)
分析:本题要找的最大的连续区间的长度L,使得这个区间中的f[i]值最大与最小之差<=Q。该区间不一定从1开始。
首先用DP求出f[i],f[i]即从i点出发能走的最长距离。
然后用RMQ来解决每个询问。
1. 求f[i]。求法请见HDU2196:
http://blog.csdn.net/u013480600/article/details/21831363
2. RMQ处理询问。假设对于当前询问为Q值,那么我们设定两个int指针l和r,初值都为1,最终值为n(共n个节点)。
我们每次都检查从l开始,能到达的最远r点,使得getMax(l,r)-getMin(l,r)的值<=Q。我们每次都固定l,然后让r尽量往后走,只要距离差<=Q就行。如果距离差>Q了,那么表示r-1已经是当前l位置能走的最远距离了,用这个数据去更新ans。所以此时我们求出了当前l能到达的最远距离,接下来我们要求l+1能到达的最远距离,当左端点是l+1时,r肯定至少都要在左端点为l时右端点能达到的最远位置上,想想是不是?这样我们对于一个询问就能在O(n)时间内解决(因为RMQ的getMax时间是O(1))。
AC代码:1343ms
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN =50000+100; int tot; int longest[MAXN]; int dist[MAXN][3]; int f[MAXN]; int head[MAXN]; int n,m; struct edge { int to; int next; int w; }edges[MAXN*2]; void add_edge(int u,int v,int w) { edges[tot].to=v; edges[tot].w=w; edges[tot].next=head[u]; head[u]=tot++; } int dfs1(int u,int fa) { if(dist[u][0]>=0)return dist[u][0]; dist[u][0]=dist[u][1]=dist[u][2]=longest[u]=0; for(int e=head[u];e!=-1;e=edges[e].next) { int v= edges[e].to; if(v==fa)continue; if(dist[u][0]<dfs1(v,u)+edges[e].w) { dist[u][1] = dist[u][0]; longest[u]=v; dist[u][0]=dfs1(v,u)+edges[e].w; } else if(dist[u][1]<dfs1(v,u)+edges[e].w) dist[u][1] = dfs1(v,u)+edges[e].w; } return dist[u][0]; } void dfs2(int u,int fa) { for(int e=head[u];e!=-1;e=edges[e].next) { int v=edges[e].to; if(v==fa)continue; if(v==longest[u])dist[v][2]=max(dist[u][2],dist[u][1])+edges[e].w; else dist[v][2]=max(dist[u][2],dist[u][0])+edges[e].w; dfs2(v,u); } } int dmax[MAXN][20]; int dmin[MAXN][20]; int mm[MAXN];//mm[x]=j表数x最多取log2能到j,即2^j<=x但是2^(j+1)>x void initRMQ(int n,int d[]) { mm[0]=-1; for(int i=1;i<=n;i++) { mm[i] = (i&(i-1))==0?mm[i-1]+1:mm[i-1];//当i&(i-1)==0时,i必定为1000000这种数 dmax[i][0]=d[i]; dmin[i][0]=d[i]; } for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) { dmax[i][j] = max(dmax[i][j-1] , dmax[i+(1<<(j-1))][j-1]); dmin[i][j] = min(dmin[i][j-1] , dmin[i+(1<<(j-1))][j-1]); } } int getRMQ(int L,int R) { int k=mm[R-L+1];; return max(dmax[L][k] , dmax[R-(1<<k)+1][k]) - min(dmin[L][k] , dmin[R-(1<<k)+1][k]) ; } void solve(int q) { int l=1,r=1; int ans=1; while(l<=n&&r<=n) { while(r<=n&&getRMQ(l,r)<=q) { r++; } ans = max(ans,r-l); l++; } printf("%d\n",ans); } int main() { while(scanf("%d%d",&n,&m)==2) { if(n==0&&m==0)break; tot=0; memset(dist,-1,sizeof(dist)); memset(head,-1,sizeof(head)); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w); add_edge(v,u,w); } dfs1(1,-1); dfs2(1,-1); for(int i=1;i<=n;i++) f[i] = max(dist[i][0] , dist[i][2]); initRMQ(n,f); while(m--) { int q; scanf("%d",&q); solve(q); } } return 0; }