HDU 4123 (2011 Asia FZU contest)(树形DP + 维护最长子序列)(bfs + 尺取法)

题意:告诉一张带权图,不存在环,存下每个点能够到的最大的距离,就是一个长度为n的序列,然后求出最大值-最小值不大于Q的最长子序列的长度。

做法1:两步,第一步是根据图计算出这个序列,大姐头用了树形DP(并不懂DP),然后就是求子序列长度,其实完全可以用RMQ爆,但是大姐头觉得会超时,于是就采用维护最大,最小值(差超过Q的时候就删掉,然后记录长度)。

做法2:通过3次bfs求树的直径(为什么啊),然后RMQ求出所有区间的最大最小值

时间复杂度:290ms

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <sstream>
  4 #include <cmath>
  5 #include <cstring>
  6 #include <cstdlib>
  7 #include <string>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <queue>
 12 #include <stack>
 13 #include <algorithm>
 14 using namespace std;
 15 #define ll long long
 16 #define _cle(m, a) memset(m, a, sizeof(m))
 17 #define repu(i, a, b) for(int i = a; i < b; i++)
 18 #define repd(i, a, b) for(int i = b; i >= a; i--)
 19 #define sfi(n) scanf("%d", &n)
 20 #define sfl(n) scanf("%I64d", &n)
 21 #define pfi(n) printf("%d\n", n)
 22 #define pffi(n, m) printf("%d %d\n", n, m)
 23 #define pfl(n) printf("%I64d\n", n)
 24 #define MAXN 50005
 25 int n, m;
 26 int d[MAXN][2], cd[MAXN], dp[MAXN];
 27 bool vis[MAXN];
 28 struct P
 29 {
 30     int y, w;
 31     P(int _x = 0, int _w = 0) : y(_x), w(_w) {}
 32 };
 33 vector<P> v[MAXN];
 34 int p[MAXN];
 35 int num[MAXN];
 36 void dfs(int root)
 37 {
 38     if(vis[root]) return ;
 39     vis[root] = 1;
 40     int siz = v[root].size();
 41     repu(i, 0, siz) dfs(v[root][i].y);
 42     int maxn = 0;
 43     repu(i, 0, siz)
 44     if(maxn < d[v[root][i].y][0] + v[root][i].w)
 45     {
 46         maxn = d[v[root][i].y][0] + v[root][i].w;
 47         cd[root] = v[root][i].y;
 48     }
 49     d[root][0] = maxn;
 50     int c = 0;
 51     repu(i, 0, siz)
 52     if(c < d[v[root][i].y][0] + v[root][i].w && v[root][i].y != cd[root])
 53         c = d[v[root][i].y][0] + v[root][i].w;
 54     d[root][1] = c;
 55 }
 56 void DP(int root)
 57 {
 58     if(vis[root]) return ;
 59     vis[root] = 1;
 60     int siz = v[root].size();
 61     repu(i, 0, siz) if(!vis[v[root][i].y])
 62     {
 63         if(cd[root] != v[root][i].y)
 64             dp[v[root][i].y] = max(d[root][0], dp[root]) + v[root][i].w;
 65         else
 66             dp[v[root][i].y] = max(d[root][1], dp[root]) + v[root][i].w;
 67         DP(v[root][i].y);
 68     }
 69     return ;
 70 }
 71 int main()
 72 {
 73     while(sfi(n), sfi(m), (n + m))
 74     {
 75         memset(d,0,sizeof(d));
 76         memset(dp,0,sizeof(dp));
 77         memset(vis,0,sizeof(vis));
 78         memset(cd,0,sizeof(cd));
 79         repu(i, 0, n + 1) v[i].clear();
 80         int x, y, w;
 81         repu(i, 0, n - 1)
 82         {
 83             sfi(x), sfi(y), sfi(w);
 84             v[x].push_back(P(y, w));
 85         }
 86         vector<P>::iterator it;
 87         dfs(1);
 88         repu(i, 2, n + 1)
 89         if(!vis[i])
 90         {
 91             int siz = v[i].size();
 92             if(!siz) continue;
 93             int flag = 0;
 94             it = v[i].begin();
 95             for(; it != v[i].end(); it++)
 96             {
 97                 if(vis[it -> y])
 98                 {
 99                     flag = 1;
100                     break;
101                 }
102             }
103             v[it -> y].push_back(P(i, it -> w));
104             v[i].erase(it);
105             dfs(i);
106         }
107         memset(d,0,sizeof(d));
108         memset(dp,0,sizeof(dp));
109         memset(vis,0,sizeof(vis));
110         memset(cd,0,sizeof(cd));
111         repu(i, 1, n + 1)
112         if(!vis[i]) dfs(i);
113 
114         memset(vis,0,sizeof(vis));
115         repu(i, 1, n + 1)
116         if(!vis[i]) DP(i);
117 
118         repu(i, 1, n + 1)
119         p[i] = max(d[i][0], dp[i]);
120 
121         int Q;
122         repu(i, 0, m)
123         {
124             scanf("%d", &Q);
125             int maxnum = 0;
126             int num = 1;
127             int last = 1;
128             int maxn = p[1];
129             int minn = p[1];
130             int maxp = 1;
131             int minp = 1;
132             repu(j, 2, n + 1)
133             {
134                 if(p[j] > maxn)
135                 {
136                     if(p[j] - minn > Q)
137                     {
138                         maxnum = max(maxnum, num);
139                         num = 1;
140                         j = min(minp + 1, maxp + 1);
141                         maxn = p[j];
142                         minn = p[j];
143                         maxp = j;
144                         minp = j;
145                     }
146                     else
147                     {
148                         num++;
149                         maxn = p[j];
150                         maxp = j;
151                     }
152                 }
153                 else if(p[j] < minn)
154                 {
155                     if(maxn - p[j] > Q)
156                     {
157                         maxnum = max(maxnum, num);
158                         num = 1;
159                         j = min(minp + 1, maxp + 1);
160                         maxn = p[j];
161                         minn = p[j];
162                         maxp = j;
163                         minp = j;
164                     }
165                     else
166                     {
167                         num++;
168                         minn = p[j];
169                         minp = j;
170                     }
171                 }
172                 else
173                     num++;
174             }
175             maxnum = max(maxnum, num);
176             pfi(maxnum);
177         }
178     }
179     return 0;
180 }
树形DP+单调队列--大姐头

时间复杂度:936ms

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <queue>
  7 #define ALL(a) a.begin(), a.end()
  8 #define clr(a, x) memset(a, x, sizeof a)
  9 #define fst first
 10 #define snd second
 11 #define pb push_back
 12 #define mp make_pair
 13 using namespace std;
 14 typedef long long LL;
 15 typedef pair<int, int> pil;
 16 #define  maxn 50050
 17 int n, m, du[maxn];
 18 int d[maxn];
 19 vector<pil> G[maxn];
 20 struct RMQ
 21 {
 22     int Dp[maxn][20];
 23     int mm[maxn];
 24     void init(int n,int b[])
 25     {
 26         mm[0] = -1;
 27         for(int i = 1; i <= n; i++)
 28         {
 29             mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
 30             Dp[i][0] = b[i];
 31         }
 32         for(int j = 1; j <= mm[n]; j++)
 33             for(int i = 1; i + (1<<j) -1 <= n; i++)
 34                 Dp[i][j] = max(Dp[i][j-1],Dp[i+(1<<(j-1))][j-1]);
 35     }
 36     int rmq(int x,int y)
 37     {
 38         int k = mm[y-x+1];
 39         return max(Dp[x][k],Dp[y-(1<<k)+1][k]);
 40     }
 41 } Min,Max;
 42 int dis[maxn]= {0};
 43 bool vis[maxn]= {0};
 44 queue<int> q;
 45 
 46 int bfs(int u)
 47 {
 48     clr(dis, 0);
 49     clr(vis, 0);
 50     int ans=0, Max=0;
 51     q.push(u);
 52     dis[u]=0, vis[u]=1;
 53     while(!q.empty())
 54     {
 55         int u=q.front();
 56         q.pop();
 57         if(dis[u]>Max)
 58             Max=dis[ans=u];
 59         for(int i=0; i<G[u].size(); i++)
 60         {
 61             pil t=G[u][i];
 62             int v=t.fst, w=t.snd;
 63             if(vis[v])continue ;
 64             dis[v]=dis[u]+w;
 65             vis[v]=true;
 66             q.push(v);
 67         }
 68     }
 69     for(int i=1; i<=n; i++)
 70         d[i]=max(d[i], dis[i]);
 71     return ans;
 72 }
 73 
 74 int main()
 75 {
 76     while(~scanf("%d%d", &n, &m) && n+m)
 77     {
 78         for(int i=1; i<=n; i++)
 79         {
 80             G[i].clear();
 81             d[i]=0;
 82         }
 83         for(int i=0; i<n-1; i++)
 84         {
 85             int u, v, w;
 86             scanf("%d%d%d", &u, &v, &w);
 87             G[u].pb(mp(v, w));
 88             G[v].pb(mp(u, w));
 89         }
 90         ///每次bfs都是求出所有点到起点的距离(只有一条路,没有最大最小)
 91         ///然后返回与起点距离最大的点MAX,再求一次所有点与MAX距离最大的点。
 92         ///求3次就可以把每个点的最大距离求出来
 93         bfs(bfs(bfs(1)));
 94         Max.init(n, d);
 95         ///从最大值到最小值换成相反数即可
 96         for(int i=1; i<=n; i++)
 97             d[i]=-d[i];
 98         Min.init(n, d);
 99         while(m--)
100         {
101             int q, ans=0;
102             scanf("%d", &q);
103             int ok = 0;
104             for(int i=1, j=1; i<=n; i++)
105             {
106                 ///原来是尺取法,傻傻的我以为完全暴力
107                 ///j只是从1开始,然后只是增加,一直到等于n
108                 while(j<=n && Max.rmq(i, j)+Min.rmq(i, j)<=q)
109                     ans=max(ans, j-i+1), j++;
110             }
111             printf("%d\n", ans);
112         }
113     }
114     return 0;
115 }
3次bfs + 尺取法----SX神

 

posted @ 2015-08-07 20:26  一麻袋码的玛侬  阅读(248)  评论(0编辑  收藏  举报