链接:新疆大学生程序设计大赛 H - Magic Transport
线段树做法
分析
- 就是说当前在第 i i i 个的时候,在 [ 1 , i − 1 ] [1, i - 1] [1,i−1] 里去找最多的不超过 m − a [ i ] m - a[i] m−a[i] 的个数。
- 暴力的想法,就是每当我们到 i i i 的时候, [ 1 , i − 1 ] [1, i - 1] [1,i−1] 都已经按照升序排序好了,那么直接二分就好了。(当然暴力是会寄的)
思路
- 定义一个二元组 ( a , b ) (a,b) (a,b) , a a a 表示重量, b b b 表示排序后的位置。
- 更新就单点修改 b b b 位置,这个 b b b 就如我们暴力的想法一样相当于是到 i i i 时 , [ 1 , i − 1 ] [1, i - 1] [1,i−1] 都已经排好序了。
- 查询就二分线段树,细节看 c o d e code code。
//道可道非常道,名可名非常名
#include <bits/stdc++.h>
using ll = long long;
template<class Info>
struct SegmentTree {
#define ls i << 1
#define rs i << 1 | 1
const int N;
std::vector<Info> seg;
SegmentTree(int _) : N(_), seg((_ + 1) << 4) {}
SegmentTree(std::vector<int> a) : SegmentTree(int(a.size())) {
std::function<void(int, int, int)> build = [&](int i, int l, int r) {
seg[i] = {l, r};
if (l == r) {
// seg[i].max = a[i - 1];
return ;
}
int mid = (l + r) / 2;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(i);
};
build(1, 1, N);
}
void pushup(int i) {
// seg[i] = seg[ls] + seg[rs];
seg[i].sum = seg[ls].sum + seg[rs].sum;
seg[i].max = seg[ls].max + seg[rs].max;
}
void modify(int i, int ind, ll v) {
if (seg[i].l == seg[i].r) {
seg[i].max = 1;
seg[i].sum = v;
return ;
}
if (ind <= seg[ls].r) {
modify(ls, ind, v);
} else {
modify(rs, ind, v);
}
pushup(i);
}
ll query(int i, int l, int r) {
if (l <= seg[i].l and seg[i].r <= r) {
return seg[i].max;
}
ll res = -1e18;
if (l <= seg[ls].r) {
res = std::max(res, query(ls, l, r));
}
if (r >= seg[rs].l) {
res = std::max(res, query(rs, l, r));
}
return res;
}
ll Query(int i, ll q) {
if (seg[i].l == seg[i].r) {
return q >= seg[i].sum ? seg[i].max : 0ll;
}
if (q >= seg[ls].sum) { // 大于等于左区间重量则左区间全满足,则加上左区间数量 并 查询右区间
return seg[ls].max + Query(rs, q - seg[ls].sum); // 此时 q 应减去左区间重量
} else {
return Query(ls, q); // 小于左区间重量则继续递归左区间
}
}
};
struct Info {
int l, r;
ll sum, max;
};
Info operator + (const Info &u, const Info &v) {
Info res = {};
res.l = u.l;
res.r = v.r;
res.sum = u.sum + v.sum;
res.max = std::max(u.max, v.max);
return res;
}
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::array<int, 2>> ord(n + 1);
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
ord[i][0] = a[i];
ord[i][1] = i;
}
std::sort(ord.begin() + 1, ord.end());
std::map<std::array<int, 2>, int> map;
for (int i = 1; i <= n; ++i) {
map.insert({ord[i], i}); // 此时map[ord[i]] 就是文中的 b
}
std::vector<int> SEG(n);
SegmentTree<Info> seg(SEG);
for (int i = 1; i <= n; ++i) {
if (i == 1) {
std::cout << "0 ";
} else {
if (m - a[i] >= 0) {
std::cout << i - 1 - seg.Query(1, m - a[i]) << " ";
} else {
std::cout << "0 ";
}
}
seg.modify(1, map[{a[i], i}], a[i]);
}
std::cout << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
//