线段树dp,有一个数组,从i->j必须满足 abs(a[i]-a[j])>=h。求这样可以最多跳多少步。首先想到的是最简单的 n^2dp,不多说。显然需要优化下,在这里就用到线段树了,如果当前位置在a[i],那么只要查询大于等于a[i]+h中最大的高度,和 小于等于a[i]-h的最大高度,就可以了,然后更新下高度为a[i]时候可以到达的最大步数。需要离散化处理下,unique lower_bound upper_bound需要很熟练。下面的代码只是求了最大的步数,没有输出路径。
线段树好久没写,也要注意下,idx>=1,l和r表示是所有的范围,都是取闭区间。
#include <iostream> #include <algorithm> #include <cmath> #include <string> #include <vector> #include <cassert> #include <stack> #include <map> using namespace std; typedef long long ll; int segtree[410000]; //idx >=1 void update(int idx, int pos, int val,int l, int r){ //cout << idx << endl; if (l == pos && r == pos) { segtree[idx] = max(segtree[idx], val); return; } int mid = (l + r) /2; if (mid < pos) update(idx * 2 + 1, pos, val, mid+1, r); else update(idx * 2, pos, val, l, mid); segtree[idx] = max(segtree[idx * 2], segtree[idx * 2 + 1]); } //[x,y] 找最大 int getMax(int idx, int x,int y,int l,int r){ if (x <= l&&y >= r) return segtree[idx]; if (y<l || x>r) return 0; int mid = (l + r) / 2; return max(getMax(idx * 2, x, y, l, mid), getMax(idx * 2+1, x, y, mid + 1, r)); } int dp[110000]; int main(){ int n, h; while (cin >> n >> h){ vector<int>height(n); for (int i = 0; i < n; i++) cin >> height[i]; map<int, int>posma; vector<int>tmp_cpy,unique_height; tmp_cpy = height; sort(height.begin(), height.end()); height.erase(unique(height.begin(), height.end()),height.end()); for (int i = 0; i < tmp_cpy.size(); i++){ int idx = lower_bound(height.begin(), height.end(), tmp_cpy[i]+h) - height.begin(); //cout <<"big:" <<idx << endl; int ans = 0; if (idx < height.size()){ ans = getMax(1, idx+1, height.size(), 1, height.size()); } idx = upper_bound(height.begin(), height.end(), tmp_cpy[i] - h) - height.begin(); //cout <<"small "<< idx << endl; if (idx < height.size()&&idx>0) ans = max(ans, getMax(1, 1, idx, 1, height.size())); idx = lower_bound(height.begin(), height.end(), tmp_cpy[i]) - height.begin(); //ma[idx + 1] = i; update(1, idx+1, ans + 1, 1, height.size()); } cout << getMax(1, 1, height.size(), 1, height.size()); } }