zoj 3349 Special Subsequence 【离散化二分 + 线段树优化dp】

Special Subsequence

Time Limit: 5 Seconds       Memory Limit: 32768 KB

There a sequence S with n integers , and A is a special subsequence that satisfies |Ai-Ai-1| <= d ( 0

Now your task is to find the longest special subsequence of a certain sequence S

Input

There are no more than 15 cases , process till the end-of-file

The first line of each case contains two integer n and d ( 1<=n<=100000 , 0<=d<=100000000) as in the description.

The second line contains exact n integers , which consist the sequnece S .Each integer is in the range [0,100000000] .There is blank between each integer.

There is a blank line between two cases

Output

For each case , print the maximum length of special subsequence you can get.

Sample Input

5 2
1 4 3 6 5

5 0
1 2 3 4 5

Sample Output

3
1


定义D序列:序列里相邻元素差的绝对值不超过d。


题意:给定n个元素组成的序列a[],求最长的D序列。


思路:考虑升序排列的序列,那么则有dp[i] = max(dp[j]) (l <= j <= r)。其中a[l]为大于或者等于a[i]-d的第一个数,a[r]为小于或者等于a[i]+d的最后一个数。维护升序序列,并不丢失序列元素的下标,可以先将坐标离散化。考虑对当前元素a[i]的处理,我们只需要处理出a[l] >= a[i] - d,a[r] <= a[i] + d以及a[i]在离散化序列中的下标L, R, P,用线段树维护[L, R]区间的最大值,更新到P对应的区间上。只要在这个过程中维护序列长度即可。


偷懒用了C++lower_boundWA了两次。还是自己手写好。。。

AC代码:


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f
#define eps 1e-4
#define MAXN (200000+10)
#define MAXM (100000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
using namespace std;
int a[MAXN], rec[MAXN];
int dp[MAXN];
struct Tree
{
    int l, r;
    int Max;
};
Tree tree[MAXN<<2];
void PushUp(int o){
    tree[o].Max = max(tree[ll].Max, tree[rr].Max);
}
void Build(int o, int l, int r)
{
    tree[o].l = l; tree[o].r = r;
    tree[o].Max = 0;
    if(l == r)
        return ;
    int mid = (l + r) >> 1;
    Build(lson); Build(rson);
    PushUp(o);
}
void update(int o, int pos, int v)
{
    if(tree[o].l == tree[o].r)
    {
        tree[o].Max = v;
        return ;
    }
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(pos <= mid)
        update(ll, pos, v);
    else
        update(rr, pos, v);
    PushUp(o);
}
int Query(int o, int L, int R)
{
    if(L <= tree[o].l && R >= tree[o].r)
        return tree[o].Max;
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid)
        return Query(ll, L, R);
    else if(L > mid)
        return Query(rr, L, R);
    else
        return max(Query(ll, L, mid), Query(rr, mid+1, R));
}
int Findleft(int val, int l, int r)
{
    int ans;
    while(r >= l)
    {
        int mid = (l + r) >> 1;
        if(rec[mid] >= val)
        {
            r = mid-1;
            ans = mid;
        }
        else
            l = mid+1;
    }
    return ans;
}
int Findright(int val, int l, int r)
{
    int ans;
    while(r >= l)
    {
        int mid = (l + r) >> 1;
        if(rec[mid] <= val)
        {
            l = mid+1;
            ans = mid;
        }
        else
            r = mid-1;
    }
    return ans;
}
int Findpos(int val, int l, int r)
{
    while(r >= l)
    {
        int mid = (l + r) >> 1;
        if(rec[mid] == val)
            return mid;
        else if(rec[mid] > val)
            r = mid-1;
        else
            l = mid+1;
    }
}
int main()
{
    int n, d;
    while(scanf("%d%d", &n, &d) != EOF)
    {
        int len = 1;
        for(int i = 1; i <= n; i++)
        {
            Ri(a[i]);
            rec[len++] = a[i];
        }
        sort(rec+1, rec+len);
        int R = 2;
        for(int i = 2; i < len; i++)
            if(rec[i] != rec[i-1])
                rec[R++] = rec[i];
        sort(rec+1, rec+R);
        Build(1, 1, R-1);
        int ans = 0; CLR(dp, 0);
        for(int i = 1; i <= n; i++)
        {
//            int l = lower_bound(rec+1, rec+R-1, a[i] - d) - rec;
//            int r = lower_bound(rec+1, rec+R-1, a[i] + d) - rec;
//            int p = lower_bound(rec+1, rec+R-1, a[i]) - rec;
            int l = Findleft(a[i]-d, 1, R-1);
            int r = Findright(a[i]+d, 1, R-1);
            int p = Findpos(a[i], 1, R-1);
            dp[i] = Query(1, l, r) + 1;
            update(1, p, dp[i]);
            ans = max(ans, dp[i]);
        }
        Pi(ans);
    }
    return 0;
}



你可能感兴趣的:(线段树,二分,离散化,我就是DP)