【DBSDFZOJ 4409】a(离散化+树状数组)

来源:互联网 发布:php xss 编辑:程序博客网 时间:2024/06/03 04:52

Description

逆序对是一个非常经典的问题,但是逆序对虽然经典,但却是一个非常困难的问题,因为一个序列的逆序对数可能太多了。所以为了简化问题,我们给定一个长度为N的序列z和一个参数k,我们希望知道有多少个(L,R)满足1 <= L < R <= N,且z1, z2, ⋯ , zL, zR, ⋯ , zN的逆序对个数不超过k。

Input

第一行两个整数N, k。
接下来一行N个整数代表序列。

Output

一行一个整数代表答案。

Sample Input 1

3 1
1 3 2

Sample Output 1

3

Sample Input 2

5 2
1 3 2 1 7

Sample Output 2

6

Data Constraint

对于100%的数据,1 <= N <= 10^5, 1 <= zi <= 10^9, k <= 10^18,有部分分。

解题思路

先离散化zi的值,用一个树状数组记录一个数前面比它大的数的个数,另一个树状数组记录一个数后面比它小的数的个数。从1至n-1枚举每一个L,R从2开始,对于每一个L,R向右找到当时逆序对数不超过k的最小值,此时的R~n都可以是可行的R的方案,加入到答案里。显然R是递增的。

代码

#include<bits/stdc++.h>#define lowbit(x) (x&(-x))#define N 100001#define LL long longusing namespace std;int n,b[N+5],a[N+5],tree[2][N+5];LL k,now=0,ans=0;inline void add(int x,int num,int opt){    while(x<=N){        tree[opt][x]+=num;        x+=lowbit(x);    }}inline int search(int x,int opt){    int re=0;    while(x){        re+=tree[opt][x];        x-=lowbit(x);    }    return re;}int main(){    scanf("%d%lld",&n,&k);    for(int i=1;i<=n;++i)        scanf("%d",&a[i]),b[i]=a[i];    sort(b+1,b+n+1);unique(b+1,b+n+1);    for(int i=1;i<=n;++i)    a[i]=lower_bound(b+1,b+n+1,a[i])-b;    for(int i=n;i>=2;--i){        now+=search(a[i]-1,1);        add(a[i],1,1);    }    LL R=2;    for(int i=1;i<=n-1;++i){        now+=search(N-a[i]-1,0)+search(a[i]-1,1);        add(N-a[i],1,0);        while((now>k || R<=i) && R<=n){            now-=search(N-a[R]-1,0)+search(a[R]-1,1);            add(a[R],-1,1);            ++R;        }        if(R==n+1)      break;        ans+=n-R+1;    }    printf("%lld",ans);    return 0;}
原创粉丝点击