线段树 HDU 2227 Find the nondecreasing subsequences

18 篇文章 0 订阅
1 篇文章 0 订阅

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2227

代码风格:notonlysuccess


题目意思:求有多少个不下降子序列

算法:线段树 离散化

思路:每一次插入前记录已经插入的数中比它小的有k个子序列满足条件,以插入值的大小建树,在该点保存的数值为k+1;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m = (l+r) >> 1
#define LL __int64

const int mod = 1000000007;

LL w[1231564], a[123546], p[456456];

void PushUp(int rt)
{
    p[rt] = p[rt << 1] + p[rt << 1 | 1];
    p[rt] %= mod;
}
void update(int d, LL k, int l, int r, int rt)
{
    if(l == r)
    {
        p[rt] += k;
        return ;
    }
    mid ;
    if(d <= m)
        update(d, k, lson);
    else update(d, k, rson);
    PushUp(rt);
}

int bin(LL key, int r)
{
    int l = 0;
    while(l <= r)
    {
        mid ;
        if(w[m] == key)
            return m;
        if(key < w[m])
            r = m - 1;
        else l = m+1;
    }
    return -1;
}

LL query(int L, int R, int l, int r, int rt )
{
    if(L <= l && r <= R)
    {
        return p[rt];
    }
    mid ;
    LL ret = 0;
    if(L <= m)
        ret += query(L, R, lson);
    if(m < R)
        ret += query(L, R, rson);
    return ret % mod;

}

int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        int i;
        for(i = 0; i < n; i ++)
        {
            scanf("%I64d", &a[i]);
            w[i] = a[i];
        }
        sort(w, w+n);
        int m = 1;
        for(i = 1; i < n; i ++)
        {
            if(w[i] != w[i-1])
                w[m ++ ] = w[i];
        }
        LL ret = 0;
        memset(p, 0, sizeof(p));
        for(i = 0; i < n; i ++)
        {
            int ww = bin(a[i], m-1);
            int k = 1;
        //    if(ww != 0)
            k = query(0, ww, 0, m-1, 1);
            update(ww, k+1, 0, m-1, 1);
            ret += k+1;
        }
        printf("%I64d\n", ret % mod);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值