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 }
时间复杂度: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 }
人生就像心电图,想要一帆风顺,除非game-over