下午这题又用优先队列写TLE,又二分TLE,想到可以线段树但是时间不够没有写。。。自闭的一下午~
题目传送门
Time Limit: 4000MS Memory Limit: 64MB
Given a sequence of n integers called W and an integer m. For each i (1 <= i <= n), you can choose some elements W k W_k Wk (1 <= k < i), and change them to zero to make ∑ j = 1 i \sum_{j=1}^i ∑j=1i W j W_j Wj<=m. So what’s the minimum number of chosen elements to meet the requirements above?
The first line contains an integer Q — the number of test cases.
For each test case:
The first line contains two integers n and m — n represents the number of elements in sequence W and m is as described above.
The second line contains n integers, which means the sequence W.
1 <= Q <= 15
1 <= n <= 2* 1 0 5 10^5 105
1 <= m <= 1 0 9 10^9 109
For each i, 1 <= W i W_i Wi <= m
For each test case, you should output n integers in one line: i-th integer means the minimum number of chosen elements W k W_k Wk (1 <= k < i), and change them to zero to make ∑ j = 1 i \sum_{j=1}^i ∑j=1i W j W_j Wj<=m.
2
7 15
1 2 3 4 5 6 7
5 100
80 40 40 40 60
0 0 0 0 0 2 3
0 1 1 2 3
二分答案+树状数组
要使删的数尽可能少,就要删尽可能大的数,即加更多小的数。
开始时先记录下数组的原始坐标,然后从小往大排序,用id[i]数组记录初始数列的第i个数排在第几位。每循环一次,就把这个数放进排好序后的位置的树状数组里,同时更新另一个树状数组(表示某个位置是否放入了数),每次二分答案求一下第一个树状数组的前缀和,使其满足题意;再利用第二个树状数组求出这段前缀和数的个数后就能计算出答案了。
代码如下:
#include
#define lowbit(x) x&(-x)
#define LL long long
using namespace std;
const int maxn = 2*1e5+100;
LL id[maxn],num[maxn];
LL s[maxn],no[maxn];
struct node{
int pos,val;
}a[maxn];
int T,n,m;
inline LL read(){
LL x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
bool cmp(node x,node y){
if (x.val==y.val) return x.pos<y.pos;
return x.val<y.val;
}
LL sum(LL *p,int x){
LL su=0;
for (;x>0;x-=lowbit(x)) su+=p[x];
return su;
}
void add(LL* p,int x,LL num){
for (;x<n;x+=lowbit(x)) p[x]+=num;
}
int main(){
T=read();
while (T--){
n=read();m=read();
memset(s,0,sizeof s);
memset(no,0,sizeof no);
for (int i=1;i<=n;i++){
num[i]=read();
a[i].val=num[i];
a[i].pos=i;
}
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++) id[a[i].pos]=i;
for (int i=1;i<=n;i++){
int now=m-num[i];
int l=0,r=n,pl;
while (l<=r){
int mid=(l+r)>>1;
long long sx=sum(s,mid);
if (sx<=now){
l=mid+1;pl=mid;
}else r=mid-1;
}
int cnt=sum(no,pl);
cout<<i-cnt-1<<" ";
add(no,id[i],1);
add(s,id[i],num[i]);
}
cout<<endl;
}
return 0;
}