#include<algorithm>
#include<iostream>
#include<iomanip>
#include<utility>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<pair<ll, ll>, ll> pa;
const ll N = 1e5 + 10, MOD = 722733748, INF = 0x7fffffffffffffff;
class cmp {
public:
bool operator() (const pa& x, const pa& y)const {
if (x.second != y.second)return x.second > y.second;
else return 0;
}
};
ll t, n, m, len, k;
ll con[4 * N], tag[4 * N];
deque<ll> indx, a;
void push_up(ll ind) {
con[ind] = con[ind * 2] + con[ind * 2 + 1];
}
void push_down(ll ind) {
if (tag[ind] == 0)return;
con[ind * 2] = 0;
tag[ind * 2] = tag[ind];
con[ind * 2 + 1] = 0;
tag[ind * 2 + 1] = tag[ind];
tag[ind] = 0;
}
void build(int l, int r, int ind) {
if (l == r) {
// con[ind]代表了当前[L,R]中数的个数,这里是indx离散化之后的[L,R]
con[ind] = 0;
tag[ind] = -1;
return;
}
ll mid = (l + r) / 2;
build(l, mid, ind * 2);
build(mid + 1, r, ind * 2 + 1);
push_up(ind);
}
void udp(int l, int r, int ind, int tmpl, int tmpr) {
if (l >= tmpl && r <= tmpr) {
con[ind] = 0;
tag[ind] = 1;
return;
}
push_down(ind);
ll mid = (l + r) / 2;
if (mid >= tmpl)udp(l, mid, ind * 2, tmpl, tmpr);
if (mid + 1 <= tmpr)udp(mid + 1, r, ind * 2 + 1, tmpl, tmpr);
push_up(ind);
}
void udpp(int l, int r, int ind, int tmpl, int tmpr) {
if (l >= tmpl && r <= tmpr) {
con[ind]++;
return;
}
ll mid = (l + r) / 2;
push_down(ind);
if (mid >= tmpl)udpp(l, mid, ind * 2, tmpl, tmpr);
if (mid + 1 <= tmpr)udpp(mid + 1, r, ind * 2 + 1, tmpl, tmpr);
push_up(ind);
}
ll query(int l, int r, int ind, int tmpl, int tmpr) {
if (l >= tmpl && r <= tmpr) {
return con[ind];
}
push_down(ind);
ll mid = (l + r) / 2;
ll res = 0;
if (mid >= tmpl)res += query(l, mid, ind * 2, tmpl, tmpr);
if (mid + 1 <= tmpr)res += query(mid + 1, r, ind * 2 + 1, tmpl, tmpr);
push_up(ind);
return res;
}
bool check(ll x) {
ll cnt = 0;
ll cntk = 1;
// 线段树
// udp用于全部清0
// udpp用于单点增加1
// query就是查询范围内的数量
// check的思想就是不断贪心地去放入a原序列元素,然后统计逆序对个数
udp(1, len, 1, 1, len);
for (int i = 1; i <= n; i++) {
ll tmp = upper_bound(indx.begin(), indx.end(), a[i]) - indx.begin();
// tmp是比第一个比当前数大的位置
ll num = 0;
if (tmp <= len)num = query(1, len, 1, tmp, len);
// 每次加入一个数,就加上能和该数形成逆序对的数量num
if (cnt + num > x) {
// 如果逆序对大于x,也就是目标,我就贪心地重新开一个段
cntk++;
// 如果段的数量大于题目k的限制,说明x不可满足,返回0
if (cntk > k)return 0;
// 可以继续开一个新段,就将线段数全部清0
// 加入当前点
udp(1, len, 1, 1, len);
udpp(1, len, 1, tmp - 1, tmp - 1);
cnt = 0;
}
else {
cnt += num;
udpp(1, len, 1, tmp - 1, tmp - 1);
}
}
//最后如果全部放进去了,就表示x可以满足
return 1;
}
void solve() {
cin >> n >> k;
a.clear();
indx.clear();
a.resize(n + 1);
indx.resize(n + 1);
// a数组是储存原序列,indx数组是储存排序后的序列,离散化
for (int i = 1; i <= n; i++)cin >> a[i], indx[i] = a[i];
sort(indx.begin() + 1, indx.end());
len = unique(indx.begin() + 1, indx.end()) - indx.begin() - 1;
build(1, len, 1);
// 二分查找,查找满足check的最小数
ll l = 0, r = n * (n - 1) / 2;
while (l < r) {
ll mid = (l + r) / 2;
if (check(mid))r = mid;
else l = mid + 1;
}
cout << l << '\n';
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
// t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
/*
*/
TLE了
不是WA,我的思路应该没错?
顺便问一下为什么只能得到一个测试点结果TLE
过一段时间后会更新吗,还是一直不能查看