码迷,mamicode.com
首页 > 其他好文 > 详细

杭电多校赛三 Find the answer 离散化

时间:2019-07-30 12:53:43      阅读:73      评论:0      收藏:0      [点我收藏+]

标签:答案   数加   记录   bool   前缀   ems   while   调用   blank   

题目链接: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;
}
#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;
}

 

杭电多校赛三 Find the answer 离散化

标签:答案   数加   记录   bool   前缀   ems   while   调用   blank   

原文地址:https://www.cnblogs.com/qingjiuling/p/11269260.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!