Codeforces Round #271 (Div. 2) E 离散化+线段树



链接:戳这里


E. Pillars
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Marmot found a row with n pillars. The i-th pillar has the height of hi meters. Starting from one pillar i1, Marmot wants to jump on the pillars i2, ..., ik. (1 ≤ i1 < i2 < ... < ik ≤ n). From a pillar i Marmot can jump on a pillar j only if i < j and |hi - hj| ≥ d, where |x| is the absolute value of the number x.

Now Marmot is asking you find out a jump sequence with maximal length and print it.

Input
The first line contains two integers n and d (1 ≤ n ≤ 105, 0 ≤ d ≤ 109).

The second line contains n numbers h1, h2, ..., hn (1 ≤ hi ≤ 1015).

Output
The first line should contain one integer k, the maximal length of a jump sequence.

The second line should contain k integers i1, i2, ..., ik (1 ≤ i1 < i2 < ... < ik ≤ n), representing the pillars' indices from the maximal length jump sequence.

If there is more than one maximal length jump sequence, print any.

Examples
input
5 2
1 3 6 7 4
output
4
1 2 3 5 
input
10 3
2 1 3 6 9 11 7 3 20 18
output
6
1 4 6 7 8 9 
Note
In the first example Marmot chooses the pillars 1, 2, 3, 5 with the heights 1, 3, 6, 4. Another jump sequence of length 4 is 1, 2, 4, 5.


题意:

有n根柱子,每根柱子高度为hi。人当前在第j根柱子,可以跳到前面的任意第i根柱子,只需要满足|aj-ai|>=d

问最多能跳多少根柱子。输出答案,并输出答案跳的路径


思路:

很容易想到dp[i]:表示当前第i根柱子的最优值

那么dp[i]肯定是从前面的dp[1~j] (1<=j<i)的最优值里面继承过来,类于LIS的On*n思想,但是这样会T

考虑我们需要快速找出(1~j)中的满足,aj-ai>=d || ai-aj>=d 的最大值dp[j],发现是找出两个区间的最大值

线段树下标从小到大存柱子的高度顺序(注意是高度大小顺序),由于高度太大,这里需要离散化一下。

线段树存两个权值,分别是当前区间的最大值dp[l,r]以及当前区间最大值所在的原hi数组的下标,方便记录路径


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int n;
ll d;
ll a[100100],b[100100];
int dp[100100],pre[100100];
int tr[400100],id[400100];
void build(int root,int l,int r){
    if(l==r) {
        tr[root]=0;
        return ;
    }
    int mid=(l+r)/2;
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
}
pair<int,int> query(int root,int l,int r,int x,int y){
    if(x<=l &&y>=r){
        return make_pair(tr[root],id[root]);
    }
    int mid=(l+r)/2;
    pair<int,int> ans;
    ans=make_pair(0,0);
    if(x<=mid){
        pair<int,int> tmp=query(root*2,l,mid,x,y);
        if(ans.first<tmp.first){
            ans=tmp;
        }
    }
    if(y>mid){
        pair<int,int> tmp=query(root*2+1,mid+1,r,x,y);
        if(ans.first<tmp.first){
            ans=tmp;
        }
    }
     if(tr[root*2]>=tr[root*2+1]){
        tr[root]=tr[root*2];
        id[root]=id[root*2];
    } else {
        tr[root]=tr[root*2+1];
        id[root]=id[root*2+1];
    }
    return ans;
}
void update(int root,int l,int r,int pos,int i,int v){
    if(l==pos && r==pos){
        if(tr[root]<v){
            tr[root]=v;
            id[root]=i;
        }
        return ;
    }
    int mid=(l+r)/2;
    if(pos<=mid){
        update(root*2,l,mid,pos,i,v);
    } else if(pos>mid) update(root*2+1,mid+1,r,pos,i,v);
    if(tr[root*2]>=tr[root*2+1]){
        tr[root]=tr[root*2];
        id[root]=id[root*2];
    } else {
        tr[root]=tr[root*2+1];
        id[root]=id[root*2+1];
    }
}
void print(int x){
    if(x==0) return ;
    else print(pre[x]);
    printf("%d ",x);
}
int main(){
    scanf("%d%I64d",&n,&d);
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    for(int i=1;i<=n;i++) b[i]=a[i];
    sort(b+1,b+n+1);
    int m=unique(b+1,b+n+1)-(b+1);
    build(1,1,m);
    int ans=0,root=-1;
    for(int i=1;i<=n;i++){
        dp[i]=0;
        int L=upper_bound(b+1,b+m+1,a[i]-d)-b;
        int R=lower_bound(b+1,b+m+1,a[i]+d)-b;
        L--;
        if(L>=1){
            pair<int ,int> p=query(1,1,m,1,L);
            if(p.first+1>dp[i]){
                dp[i]=p.first+1;
                pre[i]=p.second;
            }
        }
        if(R<=m){
            pair<int,int> p=query(1,1,m,R,m);
            if(p.first+1>dp[i]){
                dp[i]=p.first+1;
                pre[i]=p.second;
            }
        }
        int x=lower_bound(b+1,b+m+1,a[i])-b;
        update(1,1,m,x,i,dp[i]);
        if(ans<dp[i]){
            ans=dp[i];
            root=i;
        }
    }
    printf("%d\n",ans);
    if(ans==0) return 0;
    print(root);
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值