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 }

 

 

你可能感兴趣的:(poj)