题目链接:点击打开链接
题意:一个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;
}