hdu 4123 Bob’s Race(树形DP+rmq)
题目链接:hdu 4123 Bob’s Race
题意:
给你n个节点,n-1条边的树,每条边有一个边权,定义dis[i]为距离i这个点最远的距离。
现在有m个询问,每个询问给一个q,然后找一段节点标号连续的点,使得max(dis[j])-min(dis[i])<=q;
问最长的一段区间。
题解:
最开始还以为这个连续指的是有边相连,然后感觉无法做啊,然后百度了一下,发现是标号的相连。
先求出每一个点的dis,如果不会,请先做hdu 2196 Computer(树形DP)
因为m比较小,我们就可以考虑对每个询问用双指针滚一下。
然后双指针滚的时候要求每段区间的最大值和最小值,所以这里用rmq预处理一下最大和最小值,
或者也可以用单调队列维护一下 都行。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 const int N=5e4+7; 5 int n,m,g[N],v[2*N],nxt[N*2],w[N*2],ed,dis[N],en,mx,mxx[N][20],mii[N][20]; 6 7 void adg(int x,int y,int z){v[++ed]=y,w[ed]=z,nxt[ed]=g[x],g[x]=ed;} 8 9 void dfs(int x,int fa,int dep) 10 { 11 dis[x]=max(dis[x],dep); 12 if(dep>mx)mx=dep,en=x; 13 for(int i=g[x];i;i=nxt[i]) 14 if(v[i]!=fa)dfs(v[i],x,dep+w[i]); 15 } 16 17 void rmq(int *a,int f[][20],int k) 18 { 19 F(i,1,n)f[i][0]=a[i]; 20 for(int j=1;1<<j<n;j++)F(i,1,n) 21 if(i+(1<<j)-1<= n) 22 f[i][j]=k?max(f[i][j-1],f[i+(1<<j-1)][j-1]):min(f[i][j-1],f[i+(1<<j-1)][j-1]); 23 else break; 24 } 25 inline int find(int l,int r,int v) 26 { 27 int k=31-__builtin_clz(r-l+1); 28 return v?max(mxx[l][k],mxx[r-(1<<k)+1][k]):min(mii[l][k],mii[r-(1<<k)+1][k]); 29 } 30 31 int find(int x) 32 { 33 int l=1,r=0,ans=0,mxx=0,mii=-N; 34 while(r<n) 35 { 36 while(r<n&&(l>r||find(l,r+1,1)-find(l,r+1,0)<=x))r++; 37 ans=max(ans,r-l+1),r++; 38 if(r>n)break; 39 while(l<r&&find(l,r,1)-find(l,r,0)>x)l++; 40 ans=max(ans,r-l+1); 41 } 42 return ans; 43 } 44 45 int main() 46 { 47 while(scanf("%d%d",&n,&m),n+m) 48 { 49 memset(g,0,sizeof(g)),ed=mx=0; 50 int x,y,z; 51 F(i,1,n-1) 52 { 53 scanf("%d%d%d",&x,&y,&z); 54 adg(x,y,z),adg(y,x,z); 55 } 56 F(i,1,n)dis[i]=0; 57 dfs(1,0,0),dfs(en,0,0),dfs(en,0,0); 58 rmq(dis,mxx,1),rmq(dis,mii,0); 59 while(m--) 60 { 61 scanf("%d",&x); 62 printf("%d\n",find(x)); 63 } 64 } 65 return 0; 66 }