[CF 474E] Pillars (线段树+dp)

时间:2023-03-08 23:47:37
[CF 474E] Pillars (线段树+dp)

题目链接:http://codeforces.com/contest/474/problem/F

意思是给你两个数n和d,下面给你n座山的高度。

一个人任意选择一座山作为起始点,向右跳,但是只能跳到高度差的绝对值大于等于d的山上。

问跳过的最长路径是什么。

设dp[h[i]]是跳到第i座山的最长路径长度。

那么dp[h[i]] = max( dp[h[j]] ) + 1  ( |h[i]-h[j]| >=d && i>j )

因为要查询区间最大值,所以考虑用线段树实现。

从左向右扫,线段树seg[i]维护的是走到高度为i的山走的最长路径

那么先找出 区间 [0,h[i]-d] 的最长路径,再找出区间 [h[i]+d,n]的最长路径

然后求出最大的加1,再放入线段树的h[i]位置中。

注意要维护路径  还有离散化

 #include <bits/stdc++.h>
using namespace std;
typedef long long LL; const int MAX_N = *1e5+;
LL h[MAX_N],b[MAX_N];
// 这里写的时候偷懒了,sum代表高度对应的最长路径,maxn代表当前高度对应的最近的下标
int sum[MAX_N<<], maxn[MAX_N<<],dp[MAX_N],qq[MAX_N],n,d;
int route[MAX_N]; void push_up(int idx){
sum[idx] = max(sum[idx<<],sum[idx<<|]);
if( sum[idx<<]>sum[idx<<|] ) maxn[idx] = maxn[idx<<];
else maxn[idx] = maxn[idx<<|];
} // 更新pos的山的路径长,并且下标置为i
void update(int pos,int x,int i,int idx,int l,int r){
if( l==r ){
sum[idx] = x;
maxn[idx] = i;
return;
}
int m = l+r>>;
if( pos<=m ) update(pos,x,i,idx<<,l,m);
else update(pos,x,i,idx<<|,m+,r);
push_up(idx);
} // 传入的i是要被修改的,返回路径最长的山的位置
int query(int L,int R,int &i,int idx,int l,int r){
if( R<l||r<L ) {
i = -;
return -;
}
if( L<=l&&R>=r ) {
i = maxn[idx];
return sum[idx];
}
int m = l+r>> , res = -;
if( L<=m ) {
int s;
int Q = query(L,R,s,idx<<,l,m);
if( Q>res ){
i = s;
res = Q;
}
}
if( R>m ){
int s;
int Q = query(L,R,s,idx<<|,m+,r);
if( Q>res ) {
res = Q;
i = s;
}
}
return res;
} int main(){
memset(maxn,-,sizeof(maxn)); int ptr = ;
scanf("%d%d",&n,&d);
for(int i=;i<n;i++){
scanf("%I64d",&h[i]);
b[ptr++] = h[i];
b[ptr++] = h[i]-1LL*d;
b[ptr++] = h[i]+1LL*d;
}
sort(b,b+ptr);
int ub = unique(b,b+ptr) - b; for(int i=;i<n;i++){
int r = lower_bound(b,b+ub,h[i]+d) - b;
int lmax = -;
int rs = query(r,ptr-,lmax,,,ptr-);
int rmax = -;
int l = lower_bound(b,b+ub,h[i]-d) - b;
int ls = query(,l,rmax,,,ptr-);
qq[i] = max(ls,rs);
int t = lower_bound(b,b+ub,h[i]) - b;
update(t,qq[i]+,i,,,ptr-);
if(ls>rs){
dp[i] = rmax;
} else {
dp[i] = lmax;
}
}
int idx = maxn[];
int ED = sum[];
printf("%d\n",ED);
int ptrr = ;
route[ptrr++] = idx;
while( route[ptrr-]> ){
int s = route[ptrr-];
route[ptrr] = dp[s];
ptrr++;
}
while( route[ptrr-]< ) ptrr--;
for(int i=ptrr-;i>=;i--){
printf("%d ",route[i]+);
}
return ;
}

代码