HDUOJ 6609 Find the answer

HDUOJ 6609 Find the answer

Topic link

Problem Description

Given a sequence of n integers called W and an integer m. For each i (1 <= i <= n), you can choose some elements Wk (1 <= k < i), and change them to zero to make ∑ij=1Wj<=m. So what’s the minimum number of chosen elements to meet the requirements above?.

Input

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 elemens 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 <= 2e5
1 <= m <= 109
For each i, 1 <= Wi <= m

Output

For each test case, you should output n integers in one line: i-th integer means the minimum number of chosen elements Wk (1 <= k < i), and change them to zero to make ∑ij=1Wj<=m.

Sample Input

2  
7 15  
1 2 3 4 5 6 7  
5 100  
80 40 40 40 60

Sample Output

0 0 0 0 0 2 3  
0 1 1 2 3

The application of the weighted line segment tree is a very clever question. Let me explain the idea of ​​solving the problem~
First of all, the prefix and sum [i] sum[i] must be required .s u m [ i ] , then the sum of the numbers deleted each time must be greater thansum [i] − m sum[i]-msum[i]m , then you can consider using a weighted line segment tree, two variables, one record sum, and one record number of occurrences~

  • The update operation is very simple, add the value of the corresponding position to the array of the record sum, and the number of occurrences plus one
  • The difficulty lies in the query. The purpose of our query is to find the minimum number of elements such that the sum of the elements is greater than or equal to x = sum [i] − mx=sum[i]-mx=sum[i]m , in fact, is equivalent to constantlychecking x = sum [i] − mx=sum[i]-mon the line segment treex=sum[i]m operation until it becomes0 00 , because the minimum number of elements is required, the elements of the right subtree must be deleted first, then thexxof a certain processx , we judge the size of the sum of it and the right subtree, if it is greater than the sum, letxxx minustree [2 ∗ i + 1] tree[2*i+1]tree[2i+1 ] , and the answer plus the number of elements in the right child duoshan treecnt [2 ∗ i + 1] cnt[2*i+1]cnt[2i+1 ] ; If it is less than, then directly enter the right subtree; if a single point is found, note that the single point in the second time must be the smallest element, if it cannot be divisible, try to delete the single point afterxxx is still left, so we need to delete one more, which means we must round up

The two main operations of the weighted line segment tree are above, and these are the difficulties. If the line segment tree is still difficult to understand, it is recommended that you build a simulation example on the draft paper, and you will quickly understand it. The AC code is as follows:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int t,n,k,ans[N],cnt[N<<2];
ll m,a[N],sum=0,tree[N<<2];
vector<ll>v;
int getid(ll x){
    
    
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}

void pushup(int i)
{
    
    
    tree[i]=tree[i<<1]+tree[i<<1|1];
    cnt[i]=cnt[i<<1]+cnt[i<<1|1];
}

void build(int i,int l,int r)
{
    
    
    if(l==r)
    {
    
    
        tree[i]=cnt[i]=0;
        return ;
    }
    int mid=l+r>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    pushup(i);
}

void update(int i,int l,int r,int x)
{
    
    
    if(l==r)
    {
    
    
        tree[i]+=v[l-1];
        cnt[i]++;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) update(i<<1,l,mid,x);
    else update(i<<1|1,mid+1,r,x);
    pushup(i);
}

int query(int i,int l,int r,ll x)
{
    
    
    if(l==r) return (x+v[l-1]-1)/v[l-1];
    int mid=l+r>>1,ans=0;
    if(x<tree[i<<1|1]) ans+=query(i<<1|1,mid+1,r,x);
    else ans+=cnt[i<<1|1]+query(i<<1,l,mid,x-tree[i<<1|1]);
    return ans;
}

int main(){
    
    
    scanf("%d",&t);
    while(t--){
    
    
        v.clear();
        sum=0;
        scanf("%d%lld",&n,&m);
        for(int i=1;i<=n;i++){
    
    
            scanf("%lld",&a[i]);
            v.push_back(a[i]);
        }
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        k=v.size();
        build(1,1,k);
        for(int i=1;i<=n;i++){
    
    
            sum+=a[i];
            if(i>1) ans[i]=query(1,1,k,sum-m);
            update(1,1,k,getid(a[i]));
        }
        for(int i=1;i<=n;i++){
    
    
            printf("%d ",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_43765333/article/details/108651636