zoukankan      html  css  js  c++  java
  • 2019 Multi-University Training Contest 3 Find the answer (离散化+二分+树状数组)

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

    题目大意:给定一个含有n个数的序列,还有一个m,对于每个i(1<=i<=n)求出最少需要将前i-1个数中的多少个数改成0,才能使得前i个数的和小于m

    解题思路:很容易想到,我们应该将比较大的数变为0,答案才是最优的。所以我们直接给他们排个序离散化一下,对应它们在树上的编号,树上节点存两个东西,一个是节点的权值之和,还有一个就是包含数的个数,每次查询时,先将前i-1个数更新到树上,可以保证后面的数不影响答案,假设前i个数的和sum-m=x,则我们只要二分找到个一个最大的l,使得区间[l,n]大于等于x就可以了,这样答案就是区间[l,n]的数的个数了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+7;
    int n,m,ans[maxn];
    struct node{
        int val,id,rk;
    }a[maxn];
    bool cmp1(node x,node y){
        return x.val<y.val;
    }
    bool cmp2(node x,node y){
        return x.id<y.id;
    }
    ll sum[maxn],num[maxn];
    int Ans;
    int lowbit(int x){
        return x&(-x);
    }
    void add(int x,ll val){
        while(x<=n){
            num[x]++;
            sum[x]+=val;
            x+=lowbit(x);
        }
    }
    ll ask(int x){
        ll res=0;
        while(x){
            Ans+=num[x];
            res+=sum[x];
            x-=lowbit(x); 
        }
        return res;
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            memset(num,0,sizeof(num));
            memset(sum,0,sizeof(sum));
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i].val);
                a[i].id=i;
            }
            sort(a+1,a+1+n,cmp1);
            for(int i=1;i<=n;i++)
                a[i].rk=i;
            sort(a+1,a+1+n,cmp2);
            ll tmp=0;
            for(int i=1;i<=n;i++){
                tmp+=a[i].val;
                if(tmp<=m)ans[i]=0;
                else{
                    ll x=tmp-m;
                    int l=0,r=n;
                    Ans=0;
                    ll s1=ask(n); ll Ans1=Ans;
                    while(l<=r){
                        int mid=l+r>>1;
                        Ans=0;
                        ll s2=ask(mid); ll Ans2=Ans;
                        if(s1-s2>=x){
                            ans[i]=Ans1-Ans2;
                            l=mid+1; 
                        }else r=mid-1;
                    }
                }
            //    cout<<a[i].rk<<" "<<a[i].val<<endl;
                add(a[i].rk,a[i].val);
            }
            for(int i=1;i<=n;i++)
                printf("%d ",ans[i]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    H5 俄罗斯方块Demo
    HTML5 Web Workers
    H5 基于Web Storage 的客户端留言板
    H5 百度一下,你就知道
    H5 71-网易注册界面4
    H5 70-清除浮动方式五
    H5 69-清除浮动方式四
    H5 68-伪元素选择器
    H5 67-清除浮动方式三
    H5 66-清除浮动方式二
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/11270094.html