HDU 5141 LIS Again LIS变形+BIT

本文介绍了解决HDU5141问题的方法,该问题是关于寻找序列中具有最长递增子序列(LIS)长度的所有区间。通过枚举右端点并使用线段树和离散化技术来高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


HDU 5141
题意:给出长度为n的序列a,序列a的LIS长度为L,问有多少个区间[i,j]有长度为L的LIS.
n<=1e5,a[i]<=1e9.

枚举右端点R 然后找到最右边的一个L 使得[L,R]的子序列有长度为L的LIS. 则区间[1..L,R]都有长度为LIS的子序列.
先算dp[i] 以i结尾的LIS长度 和 rg[i]: 以i结尾子序列长度为LIS时最右的左端点 离散化后用BIT维护该段LIS最大值和最右的左端点

现在从小到大枚举区间的右端点i, 维护k<=i,dp[k]==L中最右的左端点pre,则此时左端点L可以取[1..pre]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,inf=0x3f3f3f3f;
int n,a[N],c[2][N];
int dp[N],rg[N],mx,res;
vector<int> v;
void discrete()
{
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
}
int lowbit(int x){return x&-x;}
void query(int x)
{
    for(int i=x;i>0;i-=lowbit(i))
    {
        if(c[0][i]>mx)
            mx=c[0][i],res=c[1][i];
        else if(c[0][i]==mx&&c[1][i]>res)
            res=c[1][i];
    }
}
void update(int x,int val,int rg)
{
    for(int i=x;i<N;i+=lowbit(i))
    {
        if(c[0][i]<val)
            c[0][i]=val,c[1][i]=rg;
        else if(c[0][i]==val&&c[1][i]<rg)
            c[1][i]=rg;
    }
}
int main()
{
    while(cin>>n)
    {
        int L=0;
        v.clear();
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),v.push_back(a[i]);
        discrete();
        for(int i=1;i<=n;i++)
        {
            mx=0,res=0;
            query(a[i]-1);
            dp[i]=mx+1;
            rg[i]=res?res:i;
         //   cout<<i<<' '<<dp[i]<<' '<<rg[i]<<endl;
            update(a[i],dp[i],rg[i]);
            L=max(L,dp[i]);
        }
       // cout<<L<<endl;
        ll ans=0;
        int pre=0;
        for(int i=1;i<=n;i++)
        {
            if(dp[i]==L)
                pre=max(pre,rg[i]);
            ans=(ans+pre);
        }
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值