find the answer

题目链接

题意

对于一个序列的前缀,你可以删除它前面的某些数字,是的这个前缀和小于等于$m$,询问最少删除几个。

思路

二分删除$k$个,在一棵权值线段树上维护数字个数,求出前$k$大的数字和,如果满足当前除去这些数字后的和小于等于$m$,那么就可行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
#define lson rt << 1
#define rson rt << 1 | 1
#define Lson L, mid, lson
#define Rson mid + 1, R, rson
int cnt[N << 2];
ll sum[N << 2];

void (int rt)
{
cnt[rt] = cnt[lson] + cnt[rson];
sum[rt] = sum[lson] + sum[rson];
}

void build(int L, int R, int rt)
{
if (L == R)
{
cnt[rt] = 0;
sum[rt] = 0;
return;
}
int mid = (L + R) >> 1;
build(Lson);
build(Rson);
push_up(rt);
}
vector<int> des;
void update(int v, int L, int R, int rt)
{
if (L == R)
{
cnt[rt]++;
sum[rt] += des[v - 1];
return;
}
int mid = (L + R) >> 1;
if (v <= mid)
update(v, Lson);
else
update(v, Rson);
push_up(rt);
}
ll query(int k, int L, int R, int rt)
{

if (L == R)
{
ll t = k * 1ll * des[L - 1];
//printf("t %lld %dn", t, des[L - 1]);
return t;
}
if (sum[rt] == 0)
return 0;
if (k == cnt[rt])
return sum[rt];
int mid = (L + R) >> 1;
if (k <= cnt[rson])
return query(k, Rson);
ll ans = query(cnt[rson], Rson) + query(k - cnt[rson], Lson);
//printf("l %d, r %d, ans %lldn", L, R, ans);
return ans;
}

int a[N];
template<class T>
void read(T& ret)
{
ret = 0;
char c;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9')
{
ret = ret * 10 + c - '0';
c = getchar();
}
}

int get_id(int v)
{
return lower_bound(des.begin(), des.end(), v) - des.begin() + 1;
}

int main()
{
int T;
read(T);
while (T--)
{
int n;
ll m;
read(n);
read(m);
des.clear();
for (int i = 1; i <= n; i++)
{
read(a[i]);
des.push_back(a[i]);
}
sort(des.begin(), des.end());
des.erase(unique(des.begin(), des.end()), des.end());
build(1, des.size(), 1);
ll pre = 0;
for (int i = 1; i <= n; i++)
{
if (i > 1)
{
int l = 0, r = i - 1;
while (l < r)
{
int mid = (l + r) >> 1;
//printf("mid %d, query %dn", mid, query(mid, 1, des.size(), 1));
ll ret = query(mid, 1, des.size(), 1);
if (pre - ret + a[i] <= m)
{
r = mid;
}
else
{
l = mid + 1;
}
}
printf("%d ", l);
}
else
{
printf("0 ");
}
update(get_id(a[i]), 1, des.size(), 1);
pre += a[i];
}
putchar('n');
}
return 0;
}