zoukankan      html  css  js  c++  java
  • LibreOj 6279数列分块入门 3 练习了一下set

    题目链接:https://loj.ac/problem/6279

    推荐博客:https://blog.csdn.net/qq_36038511/article/details/79725027

    这题区间查询某个数字x的前驱(区间里比x小的最大的数),我用的是二分,自己手写二分的时候一直用的是没有排序的数组,好无语,后面又用set做了一遍,熟系一下set。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<cstdio>
    #include<string>
    #include<deque> 
    using namespace std;
    typedef long long LL;
    #define eps 1e-8
    #define INF 0x3f3f3f3f
    #define maxn 50005*2
    /*struct point{
        int u,w;
    };
    bool operator <(const point &s1,const point &s2)
    {
        if(s1.w!=s2.w)
        return s1.w>s2.w;
        else
        return s1.u>s2.u;
    }*/
    int n,m,k,t,block;
    int a[maxn],tag[maxn],lump[maxn];
    vector<int>ve[510];
    void update(int x)
    {
        ve[x].clear();//把第x块原来的值清除 
        for(int i=(x-1)*block+1;i<=min(x*block,n);i++)//这里要加min,因为第x块可能是最后一块并且是不完整的 
        ve[x].push_back(a[i]);//把增加了的值重新压入 
        sort(ve[x].begin(),ve[x].end());//排序 
    }
    void add(int l,int r,int c)
    {
        for(int i=l;i<=min(lump[l]*block,r);i++)//暴力更新左边不完整的块 
        a[i]+=c;
        update(lump[l]);//更新值并且重新排序 
        if(lump[l]!=lump[r])
        {
            for(int i=(lump[r]-1)*block+1;i<=r;i++)//暴力更新右边不完整的块
            a[i]+=c;
            update(lump[r]);
        }
        for(int i=lump[l]+1;i<=lump[r]-1;i++)
        tag[i]+=c;
     }
    int binary_search(int x,int w)
    {
        int l=0,r=ve[x].size()-1;
        int pos=-INF;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(ve[x][mid]>=w)
            {
                r=mid-1;
                pos=r;
            }
            else
            {
                l=mid+1;
                pos=mid;
            }
        }
        if(pos>=0&&pos<ve[x].size()&&ve[x][pos]<w)
        return ve[x][pos];
        else
        return INF;
    }
    int find(int l,int r,int c)
    {
        int ans=-1;
        for(int i=l;i<=min(lump[l]*block,r);i++)//在左边不完整的块里查找 
        {
            if(a[i]+tag[lump[l]]<c)
            ans=max(ans,a[i]+tag[lump[l]]);
        }
        if(lump[l]!=lump[r])
        {
            for(int i=(lump[r]-1)*block+1;i<=r;i++)//在右边的不完整的块里查找 
            {
                if(a[i]+tag[lump[r]]<c)
                ans=max(ans,a[i]+tag[lump[r]]);
             } 
        }
        for(int i=lump[l]+1;i<=lump[r]-1;i++)//在中间的完整的并且有序的块里二分查找 
        {
            int t=c-tag[i];    
            /*int s=lower_bound(ve[i].begin(),ve[i].end(),t)-ve[i].begin();
            if(s!=0&&tag[i]+ve[i][s-1]<c)
            ans=max(ve[i][s-1]+tag[i],ans);*/
            int s=binary_search(i,t);
            if(s+tag[i]<c)
            ans=max(ans,s+tag[i]);
        }
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        
        fill(tag,tag+maxn-1,0);
        for(int i=0;i<=n;i++)
        ve[i].clear();
        block=sqrt(n);
        
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            lump[i]=(i-1)/block+1;
            ve[lump[i]].push_back(a[i]);
        }
        for(int i=1;i<=lump[n];i++)//把每一块的值进行排序 
        sort(ve[i].begin(),ve[i].end());
        
        for(int j=1;j<=n;j++)
        {
            int op,l,r,c;
            scanf("%d%d%d%d",&op,&l,&r,&c);
            if(op==0)
            add(l,r,c);
            else
            {
                int ans=find(l,r,c);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }

    用set的代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<cstdio>
    #include<string>
    #include<deque> 
    using namespace std;
    typedef long long LL;
    #define eps 1e-8
    #define INF 0x3f3f3f3f
    #define maxn 50005*2
    /*struct point{
        int u,w;
    };
    bool operator <(const point &s1,const point &s2)
    {
        if(s1.w!=s2.w)
        return s1.w>s2.w;
        else
        return s1.u>s2.u;
    }*/
    int n,m,k,t,block;
    int a[maxn],tag[maxn],lump[maxn];
    set<int>se[510];
    void add(int l,int r,int c)
    {
        for(int i=l;i<=min(lump[l]*block,r);i++)//暴力更新左边不完整的块 
        {
            se[lump[l]].erase(a[i]);
            a[i]+=c;
            se[lump[l]].insert(a[i]);
        }
        if(lump[l]!=lump[r])
        {
            for(int i=(lump[r]-1)*block+1;i<=r;i++)//暴力更新右边不完整的块
            {
                se[lump[r]].erase(a[i]);
                a[i]+=c;
                se[lump[r]].insert(a[i]);
            }
        }
        for(int i=lump[l]+1;i<=lump[r]-1;i++)
        tag[i]+=c;
     }
    int find(int l,int r,int c)
    {
        int ans=-1;
        for(int i=l;i<=min(lump[l]*block,r);i++)//在左边不完整的块里查找 
        {
            if(a[i]+tag[lump[l]]<c)
            ans=max(ans,a[i]+tag[lump[l]]);
        }
        if(lump[l]!=lump[r])
        {
            for(int i=(lump[r]-1)*block+1;i<=r;i++)//在右边的不完整的块里查找 
            {
                if(a[i]+tag[lump[r]]<c)
                ans=max(ans,a[i]+tag[lump[r]]);
             } 
        }
        for(int i=lump[l]+1;i<=lump[r]-1;i++)//在中间的完整的并且有序的块里二分查找 
        {
            int t=c-tag[i];    
            set<int>::iterator it=se[i].lower_bound(t);
            if(it==se[i].begin())
            continue;
            it--;
            ans=max(ans,tag[i]+(*it));
        }
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        
        fill(tag,tag+maxn-1,0);
        for(int i=0;i<=500;i++)
        se[i].clear();
        block=sqrt(n);
        
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            lump[i]=(i-1)/block+1;
            se[lump[i]].insert(a[i]);
        }
        for(int j=1;j<=n;j++)
        {
            int op,l,r,c;
            scanf("%d%d%d%d",&op,&l,&r,&c);
            if(op==0)
            add(l,r,c);
            else
            {
                int ans=find(l,r,c);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    PHP输出日志,json美化
    php获取项目路径
    16进制颜色,正则
    doctrine/instantiator
    cn.archive.ubuntu.com 慢的问题
    yzalis/identicon 像素头像
    Shell 判断进程是否存在
    shell 2>&1
    shell 判断是否继续
    shell
  • 原文地址:https://www.cnblogs.com/6262369sss/p/9736601.html
Copyright © 2011-2022 走看看