KunKun的征途

明天的明天,你还会送我水晶之恋吗?

导航

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

Posted on 2014-10-07 13:39  西域小车  阅读(302)  评论(0)    收藏  举报

题目链接: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]位置中。

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

 

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long LL;
  4 
  5 const int MAX_N = 3*1e5+100;
  6 LL h[MAX_N],b[MAX_N];
  7 // 这里写的时候偷懒了,sum代表高度对应的最长路径,maxn代表当前高度对应的最近的下标
  8 int sum[MAX_N<<2], maxn[MAX_N<<2],dp[MAX_N],qq[MAX_N],n,d;
  9 int route[MAX_N];
 10 
 11 void push_up(int idx){
 12     sum[idx] = max(sum[idx<<1],sum[idx<<1|1]);
 13     if( sum[idx<<1]>sum[idx<<1|1] ) maxn[idx] = maxn[idx<<1];
 14     else maxn[idx] = maxn[idx<<1|1];
 15 }
 16 
 17 // 更新pos的山的路径长,并且下标置为i
 18 void update(int pos,int x,int i,int idx,int l,int r){
 19     if( l==r ){
 20         sum[idx] = x;
 21         maxn[idx] = i;
 22         return;
 23     }
 24     int m = l+r>>1;
 25     if( pos<=m ) update(pos,x,i,idx<<1,l,m);
 26     else update(pos,x,i,idx<<1|1,m+1,r);
 27     push_up(idx);
 28 }
 29 
 30 // 传入的i是要被修改的,返回路径最长的山的位置
 31 int query(int L,int R,int &i,int idx,int l,int r){
 32     if( R<l||r<L ) {
 33         i = -1;
 34         return -1;
 35     }
 36     if( L<=l&&R>=r ) {
 37         i = maxn[idx];
 38         return sum[idx];
 39     }
 40     int m = l+r>>1 , res = -1;
 41     if( L<=m ) {
 42         int s;
 43         int Q = query(L,R,s,idx<<1,l,m);
 44         if( Q>res ){
 45             i = s;
 46             res = Q;
 47         }
 48     }
 49     if( R>m ){
 50         int s;
 51         int Q = query(L,R,s,idx<<1|1,m+1,r);
 52         if( Q>res ) {
 53             res = Q;
 54             i = s;
 55         }
 56     }
 57     return res;
 58 }
 59 
 60 int main(){
 61     memset(maxn,-1,sizeof(maxn));
 62 
 63     int ptr = 0;
 64     scanf("%d%d",&n,&d);
 65     for(int i=0;i<n;i++){
 66         scanf("%I64d",&h[i]);
 67         b[ptr++] = h[i];
 68         b[ptr++] = h[i]-1LL*d;
 69         b[ptr++] = h[i]+1LL*d;
 70     }
 71     sort(b,b+ptr);
 72     int ub = unique(b,b+ptr) - b;
 73 
 74     for(int i=0;i<n;i++){
 75         int r = lower_bound(b,b+ub,h[i]+d) - b;
 76         int lmax = -1;
 77         int rs = query(r,ptr-1,lmax,1,0,ptr-1);
 78         int rmax = -1;
 79         int l = lower_bound(b,b+ub,h[i]-d) - b;
 80         int ls = query(0,l,rmax,1,0,ptr-1);
 81         qq[i] = max(ls,rs);
 82         int t = lower_bound(b,b+ub,h[i]) - b;
 83         update(t,qq[i]+1,i,1,0,ptr-1);
 84         if(ls>rs){
 85             dp[i] = rmax;
 86         } else {
 87             dp[i] = lmax;
 88         }
 89     }
 90     int idx = maxn[1];
 91     int ED  = sum[1];
 92     printf("%d\n",ED);
 93     int ptrr = 0;
 94     route[ptrr++] = idx;
 95     while( route[ptrr-1]>0 ){
 96         int s = route[ptrr-1];
 97         route[ptrr] = dp[s];
 98         ptrr++;
 99     }
100     while( route[ptrr-1]<0 ) ptrr--;
101     for(int i=ptrr-1;i>=0;i--){
102         printf("%d ",route[i]+1);
103     }
104     return 0;
105 }
代码