LibreOj 6279数列分块入门 3 练习了一下set

Posted 6262369sss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

以上是关于LibreOj 6279数列分块入门 3 练习了一下set的主要内容,如果未能解决你的问题,请参考以下文章

LOJ#6279. 数列分块入门 3

Loj 6279. 数列分块入门 3

数列分块入门1-9 LibreOJ

LibreOJ 6285. 数列分块入门 9

#6279. 数列分块入门 3(询问区间内小于某个值 xx 的前驱(比其小的最大元素))

LibreOJ - 6277 数列分块入门 1(分块模板)