HDU 6609 Find the answer(权值线段树+二分)

题目链接

题解思路:对于每个位置,求出需要减掉的数 然后在权值线段树上进行二分找答案。

#include<bits/stdc++.h>

using namespace std;

#define maxn 200005
#define ll long long
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
typedef pair<int,int> PII;
const int mod = 1e9+7;

int n,m;
ll a[maxn],b[maxn],num[maxn<<2],sum[maxn<<2],atag[maxn<<2];

void Pushup(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    num[rt]=num[rt<<1]+num[rt<<1|1];
}

void Build(int l,int r,int rt){
    num[rt]=sum[rt]=0;
    if(l==r)return ;
    int mid=(l+r)>>1;
    Build(ls);
    Build(rs);
}

void Update(int l,int r,int rt,int pos){
    if(l==r&&l==pos){
        sum[rt]+=b[pos];
        num[rt]++;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)Update(ls,pos);
    else Update(rs,pos);
    Pushup(rt);
}

int Query(int l,int r,int rt,ll ss){
    if(l==r){
        int ans=ss/b[l];
        if(ss%b[l])ans++;
        return ans;
    }
    int mid=(l+r)>>1;
    if(sum[rt<<1|1]>=ss)return Query(rs,ss);
    else{
        int ans=num[rt<<1|1];
        ans+=Query(ls,ss-sum[rt<<1|1]);
        return ans;
    }
}

int main()
{
    int t;cin>>t;
    while(t--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+n+1);
        int nn=unique(b+1,b+n+1)-(b+1);
        Build(1,nn,1);
        ll Sum=0;
        for(int i=1;i<=n;i++){
            Sum+=a[i];
            if(Sum<=m){
                printf("0 ");
                int pos=lower_bound(b+1,b+nn+1,a[i])-b;
                Update(1,nn,1,pos);
            }
            else{
                ll ss=Sum-m;
                printf("%d ",Query(1,nn,1,ss));
                int pos=lower_bound(b+1,b+nn+1,a[i])-b;
                Update(1,nn,1,pos);
            }
        }
        printf("
");
    }
}
原文地址:https://www.cnblogs.com/Mmasker/p/11917469.html