#include using namespace std; struct SegTree { int n; vector cnt; // 個数 vector sum; // 値の総和 vector lazy; // この区間は全消去されたか vector vals; // 1-indexed compressed values SegTree() : n(0) {} SegTree(const vector& v) { init(v); } static long long mul(long long a, long long b) { return (long long)((__int128)a * b); } void init(const vector& v) { vals = v; // vals[1..n] を使う n = (int)vals.size() - 1; cnt.assign(4 * max(1, n) + 5, 0); sum.assign(4 * max(1, n) + 5, 0); lazy.assign(4 * max(1, n) + 5, 0); } void clear_node(int p) { cnt[p] = 0; sum[p] = 0; lazy[p] = 1; } void push(int p) { if (!lazy[p]) return; clear_node(p << 1); clear_node(p << 1 | 1); lazy[p] = 0; } void pull(int p) { cnt[p] = cnt[p << 1] + cnt[p << 1 | 1]; sum[p] = sum[p << 1] + sum[p << 1 | 1]; } void add(int p, int l, int r, int idx, long long delta) { if (l == r) { cnt[p] += delta; sum[p] += mul(delta, vals[l]); return; } push(p); int m = (l + r) >> 1; if (idx <= m) add(p << 1, l, m, idx, delta); else add(p << 1 | 1, m + 1, r, idx, delta); pull(p); } void add(int idx, long long delta) { add(1, 1, n, idx, delta); } // 最小 k 個を削除し、その総和を返す long long take_smallest(int p, int l, int r, long long k) { if (k == 0 || cnt[p] == 0) return 0; if (l == r) { long long take = k; cnt[p] -= take; long long res = mul(take, vals[l]); sum[p] -= res; return res; } push(p); int m = (l + r) >> 1; long long res = 0; if (cnt[p << 1] >= k) { res = take_smallest(p << 1, l, m, k); } else { long long leftCnt = cnt[p << 1]; res += sum[p << 1]; clear_node(p << 1); res += take_smallest(p << 1 | 1, m + 1, r, k - leftCnt); } pull(p); return res; } long long take_smallest(long long k) { if (k == 0) return 0; return take_smallest(1, 1, n, k); } // 最大 k 個を削除し、その総和を返す long long take_largest(int p, int l, int r, long long k) { if (k == 0 || cnt[p] == 0) return 0; if (l == r) { long long take = k; cnt[p] -= take; long long res = mul(take, vals[l]); sum[p] -= res; return res; } push(p); int m = (l + r) >> 1; long long res = 0; if (cnt[p << 1 | 1] >= k) { res = take_largest(p << 1 | 1, m + 1, r, k); } else { long long rightCnt = cnt[p << 1 | 1]; res += sum[p << 1 | 1]; clear_node(p << 1 | 1); res += take_largest(p << 1, l, m, k - rightCnt); } pull(p); return res; } long long take_largest(long long k) { if (k == 0) return 0; return take_largest(1, 1, n, k); } }; struct Day { int A, C; long long B, D; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { int N; long long K; cin >> N >> K; vector days(N); vector xs; xs.reserve(2 * N); for (int i = 0; i < N; ++i) { cin >> days[i].A >> days[i].B >> days[i].C >> days[i].D; xs.push_back(days[i].A); xs.push_back(days[i].C); } sort(xs.begin(), xs.end()); xs.erase(unique(xs.begin(), xs.end()), xs.end()); // 1-indexed にする vector vals(1, 0); for (int x : xs) vals.push_back(x); SegTree seg(vals); long long inf_cnt = K; // 現在残っている「∞ の限界コスト」の個数 long long ans = 0; // = 最終的に求める S - 10^100 auto get_idx = [&](int x) { return int(lower_bound(xs.begin(), xs.end(), x) - xs.begin()) + 1; }; for (int i = 0; i < N; ++i) { int ia = get_idx(days[i].A); int ic = get_idx(days[i].C); // A_i を B_i 個追加, C_i を D_i 個追加 seg.add(ia, days[i].B); seg.add(ic, days[i].D); // 最小 D_i 個を削除して利益更新 long long removed_small_sum = seg.take_smallest(days[i].D); ans += SegTree::mul(days[i].C, days[i].D) - removed_small_sum; // 最大 B_i 個を削除 // まずは ∞ から削る long long remove_inf = min(inf_cnt, days[i].B); inf_cnt -= remove_inf; long long need_remove_finite = days[i].B - remove_inf; if (need_remove_finite > 0) { seg.take_largest(need_remove_finite); } } cout << ans << '\n'; } return 0; }