题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609
大致题意是求出每个位置i最小需要将几个位置j变为0(j<i),使得$sum_{j=1}^{i}a[j]<=m$
可以将题意换一下,删除最少的个数=i-1-保留最多的个数。
则建权值线段树,同时维护个数与权值。题目转化为用最多的权值线段树中的数凑出m-a[i]这个数。
所以就从小到大取数即可。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<vector> 7 #define lson l, mid, i<<1 8 #define rson mid + 1, r, i<<1|1 9 using namespace std; 10 typedef long long ll; 11 const int maxn = 2e5 + 10; 12 ll val[maxn * 20]; 13 int num[maxn * 20]; 14 int a[maxn], b[maxn]; 15 void up(int i) { 16 val[i] = val[i << 1] + val[i << 1 | 1]; 17 num[i] = num[i << 1] + num[i << 1 | 1]; 18 } 19 void build(int l, int r, int i) { 20 val[i] = num[i] = 0; 21 if (l == r) 22 return; 23 int mid = l + r >> 1; 24 build(lson); 25 build(rson); 26 } 27 int query(int pos, int l, int r, int i) { 28 if (val[i] <= pos) 29 return num[i]; 30 if (l == r) 31 return min(num[i], pos / b[l]);//比较该数的个数和需要多少个数 32 int mid = l + r >> 1; 33 if (val[i << 1] >= pos) 34 return query(pos, lson); 35 else 36 return num[i << 1] + query(pos - val[i << 1], rson); 37 } 38 void update(int pos, int l, int r, int i) { 39 if (l == r) { 40 val[i] += b[pos]; 41 num[i]++; 42 return; 43 } 44 int mid = l + r >> 1; 45 if (pos <= mid)update(pos, lson); 46 else update(pos, rson); 47 up(i); 48 } 49 int main() { 50 int t; 51 scanf("%d", &t); 52 while (t--) { 53 int n, m; 54 scanf("%d%d", &n, &m); 55 for (int i = 1; i <= n; i++) 56 scanf("%d", &a[i]), b[i] = a[i]; 57 sort(b + 1, b + 1 + n); 58 int k = unique(b + 1, b + 1 + n) - b - 1; 59 build(1, k, 1); 60 for (int i = 1; i <= n; i++) { 61 if (i == 1) 62 printf("0 "); 63 else 64 printf("%d%c", i - 1 - query(m - a[i], 1, k, 1), i == n ? ' ' : ' '); 65 int pos = lower_bound(b + 1, b + 1 + k, a[i]) - b; 66 update(pos, 1, k, 1); 67 } 68 } 69 }