Codeforces220 E. Little Elephant and Inversions(树状数组)

题意:

给定长度为n的数组a,和一个整数k
问有多少组(L,R),满足L<R且[1,L]与[R,n]拼起来形成序列逆序对数量不超过k

数据范围:n<=1e5,k<=1e18,a(i)<=1e9

解法:

如果(L,R)满足条件,那么(L,R+1)也满足条件
因此枚举L,找到满足条件的最小的R,那么答案就增加n-R+1

在枚举L的过程中,L右移,那么R要么不变要么右移,R的移动是单调的,
因为L右移逆序对会增加,如果逆序对总数超过k,那么R必须右移使得逆序对数量减少
那么定义一个指针R

L和R在移动过程中会导致逆序对变化,可以开两个树状数组分别存[1,L]和[R,n]中的数,
在L和R移动的时候维护[1,L]+[R,n]的逆序对变化。

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
struct BIT{
    int c[maxm];
    int lowbit(int i){
        return i&-i;
    }
    void add(int i,int t){
        while(i<maxm)c[i]+=t,i+=lowbit(i);
    }
    int ask(int i){
        int ans=0;
        while(i)ans+=c[i],i-=lowbit(i);
        return ans;
    }
}T1,T2;
int a[maxm];
int b[maxm];
int n,k;
signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    //离散化
    for(int i=1;i<=n;i++){
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    int num=unique(b+1,b+1+n)-b-1;
    for(int i=1;i<=n;i++){
        a[i]=lower_bound(b+1,b+1+num,a[i])-b;
    }
    //
    int ans=0;
    int cnt=0;//[1,l]+[r,n]的逆序对
    int r=2;//初始状态l=1,r=2
    //计算[2,n]的逆序对
    for(int i=n;i>=2;i--){
        T2.add(a[i],1);
        cnt+=T2.ask(a[i]-1);//[r,n]内部的逆序对
    }
    //
    for(int l=1;l<=n;l++){//枚举左端点l
        T1.add(a[l],1);
        cnt+=l-T1.ask(a[l]);
        cnt+=T2.ask(a[l]-1);
        while(l==r||(r<=n&&cnt>k)){//向右移动右端点r
            T2.add(a[r],-1);
            cnt-=T2.ask(a[r]-1);
            cnt-=l-T1.ask(a[r]);
            r++;
        }
        if(cnt>k||r>n)break;
        ans+=n-r+1;
    }
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值