CF474E Pillars(离散化+线段树+保存DP路径)

题意:

给出一个序列,一次跳跃只能从i跳到j,满足j>i同时abs(a[j]-a[i])>=d。询问最多可以跳几次,输出路径。

题解:

做过很多次的DP模型,需要注意的是这里的值域是1e15,需要先对数据做一个离散化,然后二分出每步DP的上下界。保存DP路径的细节在线段树和状态转移的过程中都有体现,属于常见套路!

/*
 *author: zlc
 *zucc_acm_lab
 *just do it
 */
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int inf=1e9;
const int maxn=2e5+100;
inline ll read () {ll x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;}
ll qpow (ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll n,d;
ll a[maxn];
ll t[maxn];
ll dp[maxn];
ll pre[maxn];

struct node {
    int l,r;
    pair<ll,ll> sum;
}segTree[maxn<<2];
void build (int i,int l,int r) {
    segTree[i].l=l;
    segTree[i].r=r;
    segTree[i].sum.first=-1;
    segTree[i].sum.second=-1;
    if (l==r) {
        return;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    segTree[i].sum=max(segTree[i<<1].sum,segTree[i<<1|1].sum);
}
void up (int i,ll p,ll v,ll pre) {
    if (segTree[i].l==p&&segTree[i].r==p) {
        segTree[i].sum=max(segTree[i].sum,make_pair(v,pre));
        return;
    }
    ll mid=(segTree[i].l+segTree[i].r)>>1;
    if (p<=mid)
        up(i<<1,p,v,pre);
    if (p>mid)
        up(i<<1|1,p,v,pre);
    segTree[i].sum=max(segTree[i<<1].sum,segTree[i<<1|1].sum);
}
pair<ll,ll> query (int i,int l,int r) {
    if (l>r) return make_pair(-1ll,-1ll);
    if (segTree[i].l>=l&&segTree[i].r<=r) 
        return segTree[i].sum;
    int mid=(segTree[i].l+segTree[i].r)>>1;
    pair<ll,ll> ans=make_pair(0ll,0ll);
    if (l<=mid)
        ans=max(ans,query(i<<1,l,r));
    if (r>mid)
        ans=max(ans,query(i<<1|1,l,r));
    return ans;    
}
int main () {
    n=read(),d=read();
    for (int i=1;i<=n;i++) a[i]=read(),t[i]=a[i];
    sort(t+1,t+n+1);
    int m=unique(t+1,t+n+1)-t-1;
    for (int i=1;i<=n;i++) a[i]=upper_bound(t+1,t+m+1,a[i])-t-1;
    //for (int i=1;i<=n;i++) printf("%lld ",a[i]);printf("\n"); 
    build(1,1,m+1);
    for (int i=1;i<=n;i++) {
        int Min=upper_bound(t+1,t+m+1,t[a[i]]-d)-t;
        int Max=lower_bound(t+1,t+m+1,t[a[i]]+d)-t;
        Min--;
        pair<ll,ll> t1=query(1,1,Min);
        if (t1.first+1>dp[i]) {
            dp[i]=t1.first+1;
            pre[i]=t1.second;
        }
        pair<ll,ll> t2=query(1,Max,m);
        if (t2.first+1>dp[i]) {
            dp[i]=t2.first+1;
            pre[i]=t2.second;
        }
        up(1,a[i],dp[i],i);
    }
    ll ans=0,u=-1;
    for (int i=1;i<=n;i++) {
        if (dp[i]>ans) {
            ans=dp[i];
            u=i;
        }
    }
    printf("%lld\n",ans);
    vector<int> wjm;
    while (u) {
        wjm.push_back(u);
        u=pre[u];
    }
    reverse(wjm.begin(),wjm.end());
    for (int v:wjm) printf("%d ",v);
    printf("\n");
    
}

 

posted @ 2020-09-13 16:26  zlc0405  阅读(120)  评论(0编辑  收藏  举报