【分析】先算出1~n-m的逆序对,这样同时维护了1~i的逆序对数,然后再用一个树状数组维护i~n的逆序对,然后滑动删除的区间,每次删除左边的添加右边的即可,很水。
【AC CODE】1840ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <bitset>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 1e5+10;
int n;
struct TREE{
int cnt[MAXN];
void init(){clc(cnt,0);}
int lowbit(int x){return x&-x;}
void add(int x, int v)
{
while(x <= n)
{
cnt[x] += v;
x += lowbit(x);
}
}
int query(int x)
{
int ans = 0;
while(x > 0)
{
ans += cnt[x];
x -= lowbit(x);
}
return ans;
}
}tr,tr2;
int a[MAXN];
int get_cnt(int p)
{
return tr.query(n)-tr.query(p)+tr2.query(p-1);
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int t;
scanf("%d", &t);
while(t--)
{
int len;
scanf("%d%d", &n,&len);
repe(i,1,n) scanf("%d", &a[i]);
tr.init();tr2.init();
LL ans = 0;
repe(i,1,n-len)
{
ans += tr.query(n)-tr.query(a[i]);
tr.add(a[i],1);
}
LL tmp = ans;
per(i,n-len,1)
{
int r = i+len;
tr.add(a[i],-1);
tmp += get_cnt(a[r]);
tmp -= get_cnt(a[i]);
tr2.add(a[r],1);
ans = min(ans,tmp);
}
printf("%I64d\n", ans);
}
return 0;
}