题意 思路 用线段树维护第一种做法:如果区间最大值大于
a
[
i
]
a[i]
a [ i ] 则递归左儿子;否则递归右儿子; 维护一个
1
1
1 —
n
n
n 的值为
C
C
C 的数组,最后检查多少个不是
C
C
C ,即为答案。 用
m
u
l
t
i
s
e
t
multiset
m u l t i s e t 维护第二种做法:二分查找第一个可以装下的。不过要用
m
u
l
t
i
s
e
t
multiset
m u l t i s e t 自带的
l
o
w
e
r
lower
l o w e r _
b
o
u
n
d
bound
b o u n d 否则会
T
T
T 。 代码
# include <bits/stdc++.h>
using namespace std;
const int N = 1e7 + 10 ;
# define ll long long
ll a[ N] ;
ll maxx[ N] , value[ N] ;
void pushup ( int rt)
{
maxx[ rt] = max ( maxx[ rt<< 1 ] , maxx[ rt<< 1 | 1 ] ) ;
}
void build ( int rt, int l, int r)
{
if ( l == r) {
maxx[ rt] = value[ l] ; return ;
}
int mid = ( l+ r) >> 1 ;
build ( rt<< 1 , l, mid) ;
build ( rt<< 1 | 1 , mid+ 1 , r) ;
pushup ( rt) ;
}
void query_change ( int rt, int l, int r, ll x)
{
if ( l== r) {
maxx[ rt] = maxx[ rt] - x;
value[ l] = value[ l] - x; return ;
}
int mid = ( l+ r) >> 1 ;
if ( maxx[ rt<< 1 ] >= x) {
query_change ( rt<< 1 , l, mid, x) ;
}
else {
query_change ( rt<< 1 | 1 , mid+ 1 , r, x) ;
}
pushup ( rt) ;
}
void solve ( )
{
int n; ll C; scanf ( "%d%lld" , & n, & C) ;
for ( int i= 1 ; i<= n; i++ ) scanf ( "%lld" , & a[ i] ) ;
int cnt2 = 1 ;
multiset< ll> ans2;
ans2. insert ( C) ;
for ( int i= 1 ; i<= n; i++ ) {
auto p = ans2. lower_bound ( a[ i] ) ;
if ( p == ans2. end ( ) ) {
ans2. insert ( C- a[ i] ) ; cnt2++ ;
}
else {
ans2. erase ( p) ;
ans2. insert ( * p- a[ i] ) ;
}
}
int cnt1 = 0 ;
for ( int i= 1 ; i<= n; i++ ) value[ i] = C;
build ( 1 , 1 , n) ;
for ( int i= 1 ; i<= n; i++ ) {
query_change ( 1 , 1 , n, a[ i] ) ;
}
for ( int i = 1 ; i <= n; i++ ) {
if ( value[ i] != C) cnt1++ ;
else break ;
}
printf ( "%d %d\n" , cnt1, cnt2) ;
}
int main ( )
{
# ifndef ONLINE_JUDGE
freopen ( "a.txt" , "r" , stdin ) ;
freopen ( "aout.txt" , "w" , stdout ) ;
# endif
int t; scanf ( "%d" , & t) ;
while ( t-- ) {
solve ( ) ;
}
}