POJ 4003 树形DP+RMQ
题意:
一颗树,得到每个节点可到达的最远路径长度组成的序列,每给定一个q,求最长满足{最大值-最小值<=q}的连续序列的长度
分析:
①求以每个节点出发的最长路径
dfs+树形dp:
dfs出从u节点出发,向下延伸的最长路径的长度dis[u],以及是从那条边向下延伸得到的disnum[u],还有u节点向下延伸的次长路pis[u]
从上向下DP,找到dp[u]表示从u向父节点延伸的最长路径长度
(如果这个还不熟练请移步:HDU 2196,就是求步骤①)
②维护区间最大最小的差
维护一个队列(虚拟的,真实存在的只是 h 队头指针 ,t 队尾指针 两个指针),若当前h~t不满足条件h++
否则t++
用rmq O(1)算出最值
PS:log不预处理出来会TLE,TLE两次,再度听WZC神犇说log巨慢无比,改成预处理就AC了~
XLk神犇说单纯的单调队列可以做,表示我这蒟蒻不会。。。
View Code
1 #include <cstdio> 2 #include <cmath> 3 #include <cstdlib> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 8 #define N 50010 9 #define M 5000000 10 11 using namespace std; 12 13 int to[M],next[M],len[M],head[N],cnt,dis[N],pis[N],ans[N],dp[N],fin,disnum[N],qu,n,m; 14 int pmax[N][20],pmin[N][20],lg[N*2]; 15 16 inline void add(int u,int v,int w) 17 { 18 to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++; 19 } 20 21 void dfs(int u,int pre) 22 { 23 dis[u]=pis[u]=0; 24 for(int i=head[u];~i;i=next[i]) 25 if(pre!=to[i]) 26 { 27 dfs(to[i],u); 28 if(dis[u]<dis[to[i]]+len[i]) 29 { 30 dis[u]=dis[to[i]]+len[i]; 31 disnum[u]=to[i]; 32 } 33 } 34 for(int i=head[u];~i;i=next[i]) 35 if(pre!=to[i]&&disnum[u]!=to[i]) 36 if(pis[u]<dis[to[i]]+len[i]) 37 pis[u]=dis[to[i]]+len[i]; 38 } 39 40 void find(int u,int pre) 41 { 42 for(int i=head[u];~i;i=next[i]) 43 if(to[i]!=pre) 44 { 45 if(to[i]==disnum[u]) dp[to[i]]=max(dp[u],pis[u])+len[i]; 46 else dp[to[i]]=max(dp[u],dis[u])+len[i]; 47 find(to[i],u); 48 } 49 } 50 51 int maxrmq(int l,int r) 52 { 53 int k=lg[r-l+1]; 54 return max(pmax[l][k],pmax[r-(1<<k)+1][k]); 55 } 56 57 int minrmq(int l,int r) 58 { 59 int k=lg[r-l+1]; 60 return min(pmin[l][k],pmin[r-(1<<k)+1][k]); 61 } 62 63 void pretend() 64 { 65 scanf("%d",&qu); 66 fin=0; 67 int h=1,t=1; 68 while(h<=t&&t<=n) 69 { 70 if(maxrmq(h,t)-minrmq(h,t)<=qu) 71 { 72 fin=max(fin,t-h+1); 73 t++; 74 } 75 else h++; 76 } 77 printf("%d\n",fin); 78 } 79 80 void init_rmq() 81 { 82 for(int i=1;i<=n;i++) 83 pmax[i][0]=pmin[i][0]=ans[i]; 84 for(int j=1;(1<<j)<=n;j++) 85 for(int i=1;i+(1<<j)-1<=n;i++) 86 { 87 pmax[i][j]=max(pmax[i][j-1],pmax[i+(1<<(j-1))][j-1]); 88 pmin[i][j]=min(pmin[i][j-1],pmin[i+(1<<(j-1))][j-1]); 89 } 90 } 91 92 void go() 93 { 94 memset(disnum,-1,sizeof disnum); 95 memset(dp,-1,sizeof dp); 96 dfs(1,-1); 97 dp[1]=0; 98 find(1,-1); 99 for(int i=1;i<=n;i++) ans[i]=max(dp[i],dis[i]); 100 init_rmq(); 101 for(int i=1;i<=m;i++) pretend(); 102 } 103 104 void read() 105 { 106 memset(head,-1,sizeof head); cnt=0; 107 for(int i=1,a,b,c;i<n;i++) 108 { 109 scanf("%d%d%d",&a,&b,&c); 110 add(a,b,c),add(b,a,c); 111 } 112 } 113 114 int main() 115 { 116 for(int i=1;i<100000;i++) 117 lg[i]=(i>>lg[i-1]+1)?lg[i-1]+1:lg[i-1]; 118 while(scanf("%d%d",&n,&m),n||m) 119 { 120 read(); 121 go(); 122 } 123 //system("pause"); 124 return 0; 125 }
没有人能阻止我前进的步伐,除了我自己!