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;
}