杭电2019多校第三场 HDU-6609 Find the answer(权值线段树+离散化)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609

题意:Q组样例。每组样例第一行给出n、m,接下来一行n个数(a[i])。对于每一个i\euro [1,n],输出需要删除最少的个数,使得\sum_{j=1}^{i-1}a[i]<=m

思路:对于每个i,删除最少的个数=i-1-留下的最多的个数。我们建一个权值线段树,因为1<=w[i]<=1e9而1<=n<=2e5,所以需要离散化。我们能留下的数的和最大为m-a[i]。那么题目转化为用最多的权值线段树中的数凑出m-a[i]这个数。那么我们凑的时候,如果左子树上的数的和已经够用,那么肯定只用左子树上的数;否则,我们肯定要全用左子树上的数+右子树凑出m-a[i]-左子树上数的和。注意当递归到叶节点时,那么表明我们只能用这个数去凑val,取min(tree[cur].num,val/b[tree[cur].l])即可。查询完再更新个数即可。

#include 
#define ll long long
using namespace std;
const int N = 2e5+10;
int a[N],b[N],n,nn,m;
struct node
{
    int l,r,num;
    ll val;
}tree[N<<2];
void build(int l,int r,int cur)
{
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].val=0;
    tree[cur].num=0;
    if(l==r)
        return ;
    int m=(l+r)>>1;
    build(l,m,cur<<1);
    build(m+1,r,cur<<1|1);
    return ;
}
int query(int cur,int val)
{
    if(tree[cur].val<=val)
        return tree[cur].num;
    if(tree[cur].l==tree[cur].r)
        return min(tree[cur].num,val/b[tree[cur].l]); 
    if(tree[cur<<1].val>=val)
        return query(cur<<1,val);
    else 
		return tree[cur<<1].num+query(cur<<1|1,val-tree[cur<<1].val);
}
void update(int tar,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        tree[cur].val+=b[tar];
        tree[cur].num++;
        return ;
    }

    if(tar<=tree[cur<<1].r) update(tar,cur<<1);
    else update(tar,cur<<1|1);
    
    tree[cur].val=tree[cur<<1].val+tree[cur<<1|1].val;
    tree[cur].num=tree[cur<<1].num+tree[cur<<1|1].num;
    return ;
}
int main(void)
{
    int t,pos;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        nn=unique(b+1,b+1+n)-(b+1);
        build(1,nn,1);
        
        for(int i=1;i<=n;i++)
        {
            if(i==1)
                printf("0 ");
            else printf("%d ",i-1-query(1,m-a[i]));
            pos=lower_bound(b+1,b+1+nn,a[i])-b;
            update(pos,1);
        }
        printf("\n");
    }
    return 0;
}

 

你可能感兴趣的:(线段树)