Codeforces474E - Pillars
Description
给出一个\(n(n\leq10^5)\)的正整数序列\(\{a_n\}(a_i\leq10^{15})\)和正整数\(d(d\leq10^9)\),求\(\{a_n\}\)的一个子序列\(\{b_m\}\),使得\(\forall i\in[1,m-1],|b_i-b_{i-1}|\geq d\)。
Solution
跟求最长上升子序列的方法差不多。\(f[i]\)表示目前以数值\(i\)结尾的满足要求的序列长度,则:
\[ f[i]=max\{f[j]\}+1 \quad (j\leq i-d \vee j\geq i+d) $$因为$a_i$比较大,所以先离散化一波。离散化之后求$j\leq i-d \vee j\geq i+d$时,二分一下即可,不会增加复杂度。可以用树状数组来维护$f[i]$的前缀与后缀,不过我很懒就写了线段树。
> 时间复杂度$O(nlogn)$。
##Code
```cpp
//Pillars
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long lint;
typedef std::pair<lint,int> pairI;
inline char gc()
{
static char now[1<<16],*s,*t;
if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
return *s++;
}
inline lint read()
{
lint x=0; char ch=gc();
while(ch<'0'||'9'<ch) ch=gc();
while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
return x;
}
int const N=2e5+10;
int n,d,n0; lint h[N],map[N];
int rt,cnt,ch[N][2]; pairI maxV[N];
void update(int p) {maxV[p]=max(maxV[ch[p][0]],maxV[ch[p][1]]);}
lint L,R;
void ins(int p,lint L0,lint R0,pairI x)
{
if(L==L0&&R0==L) {maxV[p]=x; return;}
for(int i=0;i<2;i++) if(!ch[p][i]) ch[p][i]=++cnt;
lint mid=L0+R0>>1;
if(L<=mid) ins(ch[p][0],L0,mid,x);
else ins(ch[p][1],mid+1,R0,x);
update(p);
}
pairI query(int p,lint L0,lint R0)
{
if(L<=L0&&R0<=R) return maxV[p];
for(int i=0;i<2;i++) if(!ch[p][i]) ch[p][i]=++cnt;
lint mid=L0+R0>>1; pairI r=pairI(0,0);
if(L<=mid) r=max(r,query(ch[p][0],L0,mid));
if(mid<R) r=max(r,query(ch[p][1],mid+1,R0));
return r;
}
int ans,seq[N],pre[N];
int main()
{
n=read(),d=read();
for(int i=1;i<=n;i++) map[i]=h[i]=read();
sort(map+1,map+n+1); n0=unique(map+1,map+n+1)-map-1;
for(int i=1;i<=n;i++) h[i]=lower_bound(map+1,map+n0+1,h[i])-map;
rt=++cnt;
for(int i=1;i<=n;i++)
{
int x=upper_bound(map+1,map+n0+1,map[h[i]]-d)-map-1;
int y=lower_bound(map+1,map+n0+1,map[h[i]]+d)-map;
int len=0; pairI t=pairI(0,0);
L=1,R=x; if(L<=R) t=query(rt,1,n0);
if(t.first>len) len=t.first,pre[i]=t.second;
L=y,R=n0; if(L<=R) t=query(rt,1,n0);
if(t.first>len) len=t.first,pre[i]=t.second;
L=h[i],ins(rt,1,n0,pairI(len+1,i));
}
L=1,R=n0; pairI t=query(rt,1,n0);
ans=t.first; printf("%d\n",ans);
for(int i=ans,x=t.second;i>=1;i--,x=pre[x]) seq[i]=x;
for(int i=1;i<=ans;i++) printf("%d ",seq[i]); puts("");
return 0;
}
```
##P.S.
老师留的那天忘记写了...真是怠惰啊
一开始懒到不想写离散化于是开了个$10^{15}$的动态开点线段树,结果`MLE`了。\]