计蒜客 The Heaviest Non-decreasing Subsequence Problem dp LIS变形 || 线段树+dp

题意:

每个数有一个val和weight,如果val < 0 weight 为 0 , val >= 1e4 weight 为5 ,其余为1.让你求一哥序列使得为weight最大并且val是不下降的.

心得:悲惨背锅。。。不知道怎么该LIS的nlogn做法。。
结果看了挺久。。
最后队友想的方法大概是
其实这个题仔细想一下就是把价值为0的去掉,然后把价值为5的分成5个1的放进去,然后求一次LIS,得到的LIS长度就是最大值了.

PS:如果价值不是5而是很大的数这个方法就不可以了.

看了别人的 ,这才知道怎么用LIS的线段树写法,这样的话可以保证在val为很大的数 的时候也可以。。。
参考http://blog.csdn.net/howardemily/article/details/78078682

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
const int maxn = 3e5+5;  
int a[maxn], v[maxn], val[maxn], Hash[maxn], id[maxn];  
int dp[maxn], treeMax[maxn*4], Max;  

void update(int root, int l, int r, int pos, int val)  
{  
    if(l == r)  
    {  
        treeMax[root] = max(treeMax[root], val);  
        return ;  
    }  
    int mid = (l+r)/2;  
    if(pos <= mid) update(root*2, l, mid, pos, val);  
    else update(root*2+1, mid+1, r, pos, val);  
    treeMax[root] = max(treeMax[root*2], treeMax[root*2+1]);  
}  

void query(int root, int l, int r, int i, int j)  
{  
    if(i <= l && j >= r)  
    {  
        Max = max(treeMax[root], Max);  
        return ;  
    }  
    int mid = (l+r)/2;  
    if(mid >= i) query(root*2, l, mid, i, j);  
    if(mid < j) query(root*2+1, mid+1, r, i, j);  
}  

int main(void)  
{  
    int x, n = 1;  
    while(~scanf("%d", &a[n]))  
    {  
        v[n] = a[n];  
        if(a[n] >= 10000) v[n] -= 10000;  
        if(a[n] >= 10000) val[n] = 5;  
        else if(a[n] >= 0) val[n] = 1;  
        else val[n] = 0;  
        Hash[n] = v[n];  
        n++;  
    }  
    n--;  
    sort(Hash+1, Hash+1+n);  
    int d = unique(Hash+1, Hash+1+n)-Hash-1;  
    for(int i = 1; i <= n; i++)  
        id[i] = lower_bound(Hash+1, Hash+1+d, v[i])-Hash;  
    int ans = 0;  
    for(int i = 1; i <= n; i++)  
    {  
        Max = 0;  
        query(1, 1, n, 1, id[i]);  
        dp[i] = Max+val[i];  
        ans = max(ans, dp[i]);  
        update(1, 1, n, id[i], dp[i]);  
    }  
    printf("%d\n", ans);  
    return 0;  
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值