树形DP+RMQ+单调队列(Bob’s Race HDU4123)
题意:有n个房子,这些房子被n-1条道路连接,有一些运动员从一个房子为起点尽可能跑最远的距离且不能通过一条道路超过两次,这些运行员不能选择同样的起点,这些运动员跑的最远距离和最近距离的差值不能超过Q,这些运行员的起点房间编号都是连续的,问最多可以选择多少个运动员跑步?
分析:就是给出一颗树形图,先用dp求出每个点所能经过的最远距离,然后用rmq求区间最值,最后用单调队列询问结果(n)的复杂度
#include"stdio.h" #include"string.h" #include"stdlib.h" #include"queue" #include"algorithm" #include"string.h" #include"string" #include"math.h" #include"vector" #include"stack" #include"map" #define eps 1e-4 #define inf 10000000 #define M 50009 #define PI acos(-1.0) using namespace std; struct node { int u,v,w,next; }edge[M*2]; int t,head[M],belong[M],dis[M][4],Log[M]; int dp_max[M][17],dp_min[M][17];//注意第二维的数组大小,太大会超时 void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w) { //edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].next=head[u]; head[u]=t++; } void dfs(int u,int f) { dis[u][0]=dis[u][1]=dis[u][2]=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==f)continue; dfs(v,u); if(dis[u][0]<dis[v][0]+edge[i].w) { dis[u][1]=dis[u][0]; dis[u][0]=dis[v][0]+edge[i].w; belong[u]=v; } else if(dis[u][1]<dis[v][0]+edge[i].w) dis[u][1]=dis[v][0]+edge[i].w; } } void dfs1(int u,int f) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==f)continue; if(v==belong[u]) dis[v][2]=max(dis[u][1],dis[u][2])+edge[i].w; else dis[v][2]=max(dis[u][0],dis[u][2])+edge[i].w; dfs1(v,u); } } void RMQ(int n) { int i,j; int m=Log[n]; for(i=1;i<=n;i++) dp_min[i][0]=dp_max[i][0]=dis[i][3]; for(j=1;j<=m;j++) { for(i=1;i<=n+1-(1<<j);i++) { dp_max[i][j]=max(dp_max[i][j-1],dp_max[i+(1<<(j-1))][j-1]); dp_min[i][j]=min(dp_min[i][j-1],dp_min[i+(1<<(j-1))][j-1]); } } } int lcp(int x,int y) { int m=Log[y-x+1]; return max(dp_max[x][m],dp_max[y+1-(1<<m)][m])-min(dp_min[x][m],dp_min[y+1-(1<<m)][m]); } int main() { int n,m,i,a,b,c; Log[0] = -1; for(int i = 1;i <M;i++) Log[i] = ((i&(i-1)) == 0)?Log[i-1]+1:Log[i-1]; while(scanf("%d%d",&n,&m),m||n) { init(); for(i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } dfs(1,-1); dfs1(1,-1); for(i=1;i<=n;i++) { dis[i][3]=max(dis[i][0],dis[i][2]); //printf("%d\n",dis[i][3]); } RMQ(n); for(i=1;i<=m;i++) { int Q; scanf("%d",&Q); int l,r; l=r=1; int ans=0; while(r<=n) { int cha=lcp(l,r); if(cha<=Q) { ans=max(ans,r-l+1); r++; } else l++; } printf("%d\n",ans); } } return 0; }