zoukankan      html  css  js  c++  java
  • loj #6279. 数列分块入门 3

    #6279. 数列分块入门 3

    题目描述

    给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的前驱(比其小的最大元素)。

    输入格式

    第一行输入一个数字 nnn。

    第二行输入 nnn 个数字,第 i 个数字为 aia_iai​​,以空格隔开。

    接下来输入 nnn 行询问,每行输入四个数字 optmathrm{opt}opt、lll、rrr、ccc,以空格隔开。

    若 opt=0mathrm{opt} = 0opt=0,表示将位于 [l,r][l, r][l,r] 的之间的数字都加 ccc。

    若 opt=1mathrm{opt} = 1opt=1,表示询问 [l,r][l, r][l,r] 中 ccc 的前驱的值(不存在则输出 −1-11)。

    输出格式

    对于每次询问,输出一行一个数字表示答案。

    样例

    样例输入

    4
    1 2 2 3
    0 1 3 1
    1 1 4 4
    0 1 2 2
    1 1 2 4

    样例输出

    3
    -1

    数据范围与提示

    对于 100% 100\%100% 的数据,1≤n≤100000,−231≤others 1 leq n leq 100000, -2^{31} leq mathrm{others}1n100000,231​​others、ans≤231−1 mathrm{ans} leq 2^{31}-1ans231​​1。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100010
    using namespace std;
    int a[maxn],b[maxn],n;
    int find(int l,int r,int c){
        int res=-1;
        while(l<=r){
            int mid=(l+r)>>1;
            if(b[mid]<c)res=b[mid],l=mid+1;
            else r=mid-1;
        }
        return res;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int op,l,r,c;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d",&op,&l,&r,&c);
            if(op==0)
                for(int j=l;j<=r;j++)
                    a[j]+=c;
            else {
                for(int j=l;j<=r;j++)
                    b[j]=a[j];
                sort(b+l,b+r+1);
                printf("%d
    ",find(l,r,c));
            }
        }
        return 0;
    }
    30分 暴力
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<set>
    #define maxn 100010
    using namespace std;
    int n,block,a[maxn],b[maxn],pos[maxn];
    set<int>s[110];
    void modify(int l,int r,int c){
        for(int i=l;i<=min(pos[l]*block,r);i++){
            s[pos[i]].erase(a[i]);
            a[i]+=c;
            s[pos[i]].insert(a[i]);
        }
        if(pos[l]!=pos[r]){
            for(int i=(pos[r]-1)*block+1;i<=r;i++){
                s[pos[i]].erase(a[i]);
                a[i]+=c;
                s[pos[i]].insert(a[i]);
            }
        }
        for(int i=pos[l]+1;i<=pos[r]-1;i++)b[i]+=c;
    }
    void query(int l,int r,int c){
        int ans=-1;
        for(int i=l;i<=min(pos[l]*block,r);i++)
            if(a[i]+b[pos[i]]<c)ans=max(ans,a[i]+b[pos[i]]);
        if(pos[l]!=pos[r])
            for(int i=(pos[r]-1)*block+1;i<=r;i++)
            if(a[i]+b[pos[i]]<c)ans=max(ans,a[i]+b[pos[i]]);
        for(int i=pos[l]+1;i<=pos[r]-1;i++){
            int x=c-b[i];
            set<int>::iterator it=s[i].lower_bound(x);
            if(it==s[i].begin())continue;
            it--;
            ans=max(ans,*it+b[i]);
        }
        printf("%d
    ",ans);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        block=1000;
        for(int i=1;i<=n;i++){
            pos[i]=(i-1)/block+1;
            s[pos[i]].insert(a[i]);
        }
        for(int i=1;i<=n;i++){
            int op,l,r,c;
            scanf("%d%d%d%d",&op,&l,&r,&c);
            if(op==0)modify(l,r,c);
            else query(l,r,c);
        }
        return 0;
    }
    100分 分块+set
  • 相关阅读:
    idou老师教你学Istio 08: 调用链埋点是否真的“零修改”?
    idou老师教你学Istio 07: 如何用istio实现请求超时管理
    idou老师教你学Istio06: 如何用istio实现流量迁移
    Strusts2笔记8--文件的上传和下载
    Strusts2笔记7--国际化
    Strusts2笔记6--拦截器
    Strusts2笔记5--数据验证
    Strusts2笔记4--类型转换器
    Struts2笔记3--获取ServletAPI和OGNL与值栈
    Struts2笔记2--动态方法调用和Action接收请求方式
  • 原文地址:https://www.cnblogs.com/thmyl/p/8964251.html
Copyright © 2011-2022 走看看