zoukankan      html  css  js  c++  java
  • 牛客网 中南林业科技大学第十一届程序设计大赛J题 二分+线段树

    https://www.nowcoder.com/acm/contest/124#question

    题意  找第一个不小于K的数的下标,然后对它前一个数加一

    解析   我们可以维护一个最大值数组  1到 i的 最大值 就是max[ i ]  二分找到最左边的值 但是 找到的前一个加1 要用线段树来维护最大值

    但是 这么写会超时。。。

    超时代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1000000007,maxn=1e6+50;
    int sum[maxn<<2];
    int a[maxn],n,m;
    void PushUP(int rt)
    {
        sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    }
    void Build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=a[l];
            return;
    
        }
        int m=(l+r)>>1;
        Build(l,m,rt<<1);
        Build(m+1,r,rt<<1|1);
        PushUP(rt);
    }
    void Update(int L,int C,int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]+=C;
            return;
        }
        int m=(l+r)>>1;
        if(L<=m)
            Update(L,C,l,m,rt<<1);
        else
            Update(L,C,m+1,r,rt<<1|1);
        PushUP(rt);
    }
    int Query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            return sum[rt];
        }
        int m=(l+r)>>1;
        int ans=-100000000;
        if(L<=m)
            ans=max(ans,Query(L,R,l,m,rt<<1));
        if(R>m)
            ans=max(ans,Query(L,R,m+1,r,rt<<1|1));
        return ans;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(sum,0,sizeof(sum));
            memset(a,0,sizeof(a));
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
            }
            Build(1,n,1);
            int l,r,k;
            while(m--)
            {
                l=1,r=n;
                scanf("%d",&k);
                //cout<<Query(1,n,1,n,1)<<endl;
                if(Query(1,n,1,n,1)<k)
                {
                    printf("are you ok
    ");
                    continue;
                }
                while(l<=r)
                {
                    int mid=(l+r)>>1;
                   // cout<<mid<<" "<<Query(1,mid,1,n,1)<<endl;
                    if(Query(1,mid,1,n,1)>=k)
                        r=mid-1;
                    else
                        l=mid+1;
                }
                printf("%d
    ",l-1);
                if(l-1)
                    Update(l-1,1,1,n,1);
            }
        }
    }

    q的 询问比较多应该是卡了常数  我们要优化一下  因为 线段树查询的时候就是二分  区间最大值是递增的 我们直接利用这个特点来操作

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1000000007,maxn=1e6+50;
    int sum[maxn<<2];
    int a[maxn],n,m;
    void PushUP(int rt)
    {
        sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    }
    void Build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=a[l];
            return;
    
        }
        int m=(l+r)>>1;
        Build(l,m,rt<<1);
        Build(m+1,r,rt<<1|1);
        PushUP(rt);
    }
    void Update(int L,int C,int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]+=C;
            return;
        }
        int m=(l+r)>>1;
        if(L<=m)
            Update(L,C,l,m,rt<<1);
        else
            Update(L,C,m+1,r,rt<<1|1);
        PushUP(rt);
    }
    int query(int L,int R,int l,int r,int rt,int p)
    {
        if(l==r)
        {
            return l;
        }
        int m=(l+r)>>1;
        if(sum[rt<<1]>=p)                    //二分查询
            return query(L,R,l,m,rt<<1,p);
        return query(L,R,m+1,r,rt<<1|1,p);
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(sum,0,sizeof(sum));
            memset(a,0,sizeof(a));
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
            }
            Build(1,n,1);
            int l,r,k;
            while(m--)
            {
                l=1,r=n;
                scanf("%d",&k);
                if(sum[1]<k)
                {
                    printf("are you ok
    ");
                    continue;
                }
                int ans=query(1,n,1,n,1,k);
                printf("%d
    ",ans-1);
                if(ans-1)
                    Update(ans-1,1,1,n,1);
            }
        }
    }

    其实 还有更简单的做法 因为 修改的是前一个值 而且找的是满足条件中最左边的 所以前一个+1 并不会 影响数组的单调性 变得只有前面一个的最大值  更新一下就好了

    #include<bits/stdc++.h>
    using namespace std;
    int a[1000005],b[1000005];
    int n,q,k;
    int main()
    {
        while(~scanf("%d%d",&n,&q))
        {
            int mx=0;
            for(int i=0;i<n;i++)
            {
                scanf("%d",&a[i]);
                b[i]=mx=max(mx,a[i]);
            }
            while(q--)
            {
                scanf("%d",&k);
                int l=lower_bound(b,b+n,k)-b;
                if(l==n){
                    printf("are you ok
    ");
                    continue;
                }
                printf("%d
    ",l);
                if(l==0)continue;
                a[l-1]++;
                b[l-1]=max(a[l-1],b[l-1]);
            }
        }
    }
  • 相关阅读:
    第三周学习进度表
    思维导图
    第二周学习进度表
    调查问卷
    微感想
    C/C++数组取值的真实实现——一个初学者的常见疑惑
    保存所有标签页,以便下次打开继续工作
    内存越界调到心态爆炸
    C语言VC6的一个asprintf实现,或:VC6上C语言使用asprintf, snprintf的坑
    Learning and Inference for Hierarchically Split PC中文字幕
  • 原文地址:https://www.cnblogs.com/stranger-/p/9085367.html
Copyright © 2011-2022 走看看