题目链接:点击打开链接
题意:一个n个数的序列,每个数有一个高度值h[i]。 求一个最长子序列,要求相邻两个数满足| h[i] - h[i-1] | >= d。 并要求打印出该序列。
类似于最长上升子序列, DP思想很简单, 但是可惜n太大了, 二重循环会超时。 所以要想办法优化掉第二层循环。
观察发现, 第二层所做的事情就是在所有满足j<i && | h[i] - h[j] | >= d 的j中找到最大的d[j]。
j < i很容易满足, 按照顺序加入就可以了, 但是还要满足大小关系, 怎么办呢?
把不等式变形就成了: h[j] <= h[i] - d 或者 h[j] >= h[i] + d 。 这不就是一个区间吗? 所以我们可以以高度为区间建一棵线段树,由于h[i]太大,先离散化一下。
可见, 线段树的区间下标并不是没有用的, 适当利用, 也可以用来维护一些信息。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; const double PI = acos(-1.0); const double eps = 1e-6; const int mod = 1000000000 + 7; const int INF = 1000000000; const int maxn = 100000 + 10; int T,m,dd,n,d[maxn],pre[maxn]; ll a[maxn],b[maxn]; struct node { int v, id; }maxv[maxn<<2]; void PushUp(int o) { if(maxv[o<<1].v <= maxv[o<<1|1].v) maxv[o] = maxv[o<<1|1]; else maxv[o] = maxv[o<<1]; } void build(int l, int r, int o) { int m = (l + r) >> 1; maxv[o].v = 0; if(l == r) return ; build(l, m, o<<1); build(m+1, r, o<<1|1); } void update(int L, int R, int v, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { if(maxv[o].v < d[v]) { maxv[o].v = d[v]; maxv[o].id = v; } return ; } if(L <= m) update(L, R, v, l, m, o<<1); if(m < R) update(L, R, v, m+1, r, o<<1|1); PushUp(o); } node query(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { return maxv[o]; } node ans ; ans.v = 0; if(L <= m) { node v = query(L, R, l, m, o<<1); if(ans.v < v.v) ans = v; } if(m < R) { node v = query(L, R, m+1, r, o<<1|1); if(ans.v < v.v) ans = v; } PushUp(o); return ans; } void print(int root) { if(d[root] == 0) return ; else print(pre[root]); if(pre[root] == 0) printf("%d",root); else printf(" %d",root); } int main() { scanf("%d%d",&n,&dd); for(int i=1;i<=n;i++) { scanf("%I64d",&a[i]); b[i] = a[i]; } sort(b+1, b+1+n); int m = unique(b+1, b+1+n) - b - 1; d[1] = 0; build(1, m, 1); int ans = 0, root = -1; for(int i=1;i<=n;i++) { d[i] = 0; int L = upper_bound(b+1, b+1+m, a[i] - dd) - b; int R = lower_bound(b+1, b+1+m, a[i] + dd) - b; L--; if(L >= 1) { node cur = query(1, L, 1, m, 1); if(cur.v + 1 > d[i]) { d[i] = cur.v + 1; pre[i] = cur.id; } } if(R <= m) { node cur = query(R, m, 1, m, 1); if(cur.v + 1 > d[i]) { d[i] = cur.v + 1; pre[i] = cur.id; } } int v = lower_bound(b+1, b+1+m, a[i]) - b; update(v, v, i, 1, m, 1); if(ans < d[i]) { ans = d[i] ; root = i; } } if(ans == 0) { printf("0\n"); return 0; } printf("%d\n",ans); print(root); printf("\n"); return 0; }