您的位置:首页 > 其它

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

2017-09-18 10:13 337 查看

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 long
using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: