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

Posted qingjiuling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杭电多校赛三 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;
#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 离散化的主要内容,如果未能解决你的问题,请参考以下文章

2019杭电多校赛第四场 HDU6621 K-th Closest Distance 主席树 二分

2021杭电多校赛2021“MINIEYE杯”中国大学生算法设计超级联赛签到题15869

2021杭电多校赛2021“MINIEYE杯”中国大学生算法设计超级联赛签到题3题

2021杭电多校赛2021“MINIEYE杯”中国大学生算法设计超级联赛签到题4题

2021杭电多校赛2021“MINIEYE杯”中国大学生算法设计超级联赛签到题5题

2021杭电多校赛2021“MINIEYE杯”中国大学生算法设计超级联赛签到题2题