Bob’s Race
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4123
题意:
有一棵树,每条边都有距离,树上每个节点都有一个权值(离这个节点最远的节点的距离)。有M个询问,每个询问有一个Q值,求最多有多少个编号连续的节点可以满足其中的最大值和最小值的差不大于Q。
题解:
根据树直径的性质求出所有节点的权值,然后尺取法找答案就行了。
代码
#include<stdio.h> #include<math.h> const int N=5e4+1; int cnt,head[N],Ev[2*N],Ew[2*N],Enext[2*N],mm,vv; int dis[N],dpmax[N][20],dpmin[N][20]; int mmax(int x,int y) { return x>y?x:y; } int mmin(int x,int y) { return x<y?x:y; } void addedge(int u,int v,int w) { Ev[cnt]=v; Ew[cnt]=w; Enext[cnt]=head[u]; head[u]=cnt++; } void Dfs(int start,int id,int fa,int cost) { for(int i=head[id];i!=-1;i=Enext[i]) { int v=Ev[i]; int w=Ew[i]; if(v==fa)continue; Dfs(start,v,id,cost+w); } if(cost>dis[id])dis[id]=cost; if(cost>mm&&id!=start)mm=cost,vv=id; } void clean(int n) { mm=0; for(int i=1;i<=n;++i) head[i]=-1,dis[i]=0; cnt=0; } void Make_Rmq(int n) { for(int i=1;i<=n;++i) { dpmax[i][0]=dis[i]; dpmin[i][0]=dis[i]; } for(int j=1;(1<<j)<=n;++j) for(int i=1;i+(1<<j)-1<=n;++i) { dpmax[i][j]=mmax(dpmax[i][j-1],dpmax[i+(1<<j-1)][j-1]); dpmin[i][j]=mmin(dpmin[i][j-1],dpmin[i+(1<<j-1)][j-1]); } } int Get_Rmq(int u,int v) { int k=0; while((1<<(k+1))<=v-u+1) k++; return mmax(dpmax[u][k],dpmax[v-(1<<k)+1][k])-mmin(dpmin[u][k],dpmin[v-(1<<k)+1][k]); } void solve() { int n,Q,x,y,z; while(~scanf("%d%d",&n,&Q)&&(n||Q)) { clean(n); for(int i=1;i<n;++i) { scanf("%d%d%d",&x,&y,&z); addedge(x,y,z); addedge(y,x,z); } Dfs(1,1,1,0); x=vv; Dfs(x,x,x,0); y=vv; Dfs(y,y,y,0); Make_Rmq(n); while(Q--) { scanf("%d",&x); vv=1;z=0; for(int i=1;i<=n;++i) { while(vv<=i&&Get_Rmq(vv,i)>x) vv++; if(i-vv+1>z)z=i-vv+1; } printf("%d ",z); } } } int main() { solve(); return 0; }