zoukankan      html  css  js  c++  java
  • 杭电多校赛三 Find the answer 离散化

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

    题意:给你一个长为n(2e5+7)的数字序列和一个数字m(1e9),对从1开始的每段区间分析(1-1,1-2...1-n),要求区间和小于m,你可以将每段区间除右端点的数置为0,每段区间输出已经将多少数置为0了

    分析:对于第i个位置,怎样选择数字才会使满足条件情况下选择数字数目最少呢?很容易想到,需要选择前i1个数中较大的数字,使其变为0

    基于这个思想,如果我们对于每个位置i都暴力去找最大的前几个数,显然会TLE!

    可以注意到,题目可以转化为前i-1个数中最多选出多少个数字和W[i]相加使得其和小于等于m(很容易想到,选择较小的数才会使选的数最多)。

    转化之后就很容易想到用线段树来维护了。 我们对给定数组进行离散化,对于离散化之后的数组建立一颗线段树,线段树上的每个节点记录区间之和以及区间内数字个数。时间复杂度:N*log(N)

    代码分析:一开始并不将线段树初始化完毕,而是一步步初始化,init()方法中nn不断乘2是为了将索引变到最下面的结点一层(如果结点一层完全的话,子节点的数目是前面所有分支数加一,因为这是一个以2为公比,1为首项的等比数列。这也是后面调用update方法时nn-1的原因),所有我们一般初始化线段树是扩大四倍。

    代码中用到了离散化,记得好好看一看。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;//这个数是1e9数量级的,且可以用memset函数 
    const int maxn=2e5+7;
    const double pi=acos(-1);
    const int mod=1e9+7;
    ll sum[4*maxn],sums[4*maxn];//分别是区间和,以及区间内数字的个数
    ll qzh[maxn];//前缀和 
    struct node{
        ll v,id;
        bool operator <(const node &x) const{
            if(v==x.v) return id<x.id;
            return v>x.v;
        }
    }a[maxn],b[maxn];
    int ans=0,nn;//ans用来记录答案 
    void init(int n){
        nn=1;
        while(nn<n) nn*=2;
    }
    void query(int k,int l,int r,ll u){
        int mid=(l+r)/2;
        if(u==0) return ;
        if(r-l==1){
            ans+=sums[k];
            return ;
        }
        if(sum[2*k]<=u) u-=sum[2*k],ans+=sums[2*k],query(k*2+1,mid,r,u);//如果左边的不够减,就搜右边的
        else{
            query(k*2,l,mid,u);//否则,就继续往左边搜 
        } 
    }
    void update(int k,int v){
        if(k==0)return;
        sum[k]+=v;
        sums[k]++;
        update(k/2,v);
    }
    int main(){
        int Q;scanf("%d",&Q);
        while(Q--){
            memset(sum,0,sizeof(sum));
            memset(sums,0,sizeof(sums));
            int n;ll m;scanf("%d %lld",&n,&m);
            init(n);
            for(int i=1;i<=n;i++){
                scanf("%lld",&a[i].v);
                b[i].id=i;
                b[i].v=a[i].v;
                qzh[i]=qzh[i-1]+a[i].v;
            }
            sort(b+1,b+1+n);
            for(int i=1;i<=n;i++){
                a[b[i].id].id=i;
            }//离散化,目的就是使a数组的id标的是其在a数组中的大小排名 
            for(int i=1;i<=n;i++){
                ll t=qzh[i]-m;
                ans=0;
                if(t>0) {
                    query(1,1,nn,t);
                }
                printf("%d ",ans);
                update(a[i].id+nn-1,a[i].v); 
            }
            cout<<endl;
        }
        return 0;
    }
  • 相关阅读:
    质心坐标(barycentric coordinates)及其应用
    用表存储代替递归算法
    Lua学习之加载其他lua文件
    Mac 端配置 Lua 环境
    聊聊二手房交易遇到的恶心事
    Mac安装Python3后,如何将默认执行的Python2改为Pyhton3
    Mac平台下部署UE4工程到iOS设备的流程
    计算椭圆运动轨迹的算法
    OpenGL中的渲染方式—— GL_TRIANGLE_STRIP
    XDRender_ShaderMode_StandardPBR 间接光照(2)-镜面反射部分(1)
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11269260.html
Copyright © 2011-2022 走看看