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

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

题目大意:中文题目

具体思路:按照上一个题的模板改就行了,但是注意在整块查找的时候的下标问题。

AC代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 # define ll long long
  4 const int maxn =  2e5+100;
  5 const int mod = 1e8+7;
  6 const int inf = 0x3f3f3f3f;
  7 ll l[maxn],r[maxn],belong[maxn];
  8 ll add[maxn],a[maxn],b[maxn];
  9 int n;
 10 void buildblock()
 11 {
 12     ll tmp=(ll)sqrt(n);
 13     ll tot=n/tmp;
 14     if(n%tmp)
 15         tot++;
 16     for(ll i=1; i<=n; i++)
 17     {
 18         belong[i]=(i-1)/tmp+1ll;
 19     }
 20     for(ll  i=1; i<=tot; i++)
 21     {
 22         l[i]=(i-1)*tmp+1ll;
 23         r[i]=i*tmp;
 24     }
 25     r[tot]=n;
 26     for(ll i=1; i<=tot; i++)
 27     {
 28         sort(b+l[i],b+r[i]+1);
 29     }
 30 }
 31 void init(int tmp){
 32     for(int i=l[tmp];i<=r[tmp];i++)b[i]=a[i];
 33     sort(b+l[tmp],b+r[tmp]+1);
 34 }
 35 void update(ll st,ll ed,ll val)
 36 {
 37     if(belong[st]==belong[ed])
 38     {
 39         for(ll i=st; i<=ed; i++)a[i]+=val;
 40         init(belong[st]);
 41         return ;
 42     }
 43     for(ll i=st; i<=r[belong[st]]; i++)a[i]+=val;
 44     init(belong[st]);
 45     for(ll  i=l[belong[ed]]; i<=ed; i++)a[i]+=val;
 46     init(belong[ed]);
 47     for(ll i=belong[st]+1; i<belong[ed]; i++)
 48         add[i]+=val;
 49 }
 50 ll ask(ll st,ll ed,ll val)
 51 {
 52     ll ans=-inf;
 53     if(belong[st]==belong[ed])
 54     {
 55         for(ll i=st; i<=ed; i++)
 56         {
 57             if(a[i]+add[belong[st]]>=val)continue;
 58             ans=max(ans,a[i]+add[belong[st]]);
 59         }
 60         return ans;
 61     }
 62     for(ll i=st; i<=r[belong[st]]; i++)
 63     {
 64         if(a[i]+add[belong[st]]>=val)continue;
 65             ans=max(ans,a[i]+add[belong[st]]);
 66     }
 67     for(ll i=l[belong[ed]]; i<=ed; i++)
 68     {
 69        if(a[i]+add[belong[ed]]>=val)continue;
 70             ans=max(ans,a[i]+add[belong[ed]]);
 71     }
 72     for(ll i=belong[st]+1; i<belong[ed]; i++)
 73     {
 74         ll tmp=val-add[i];
 75         ll id=lower_bound(b+l[i],b+r[i]+1,tmp)-(b+l[i]);
 76         if(id==0)continue;
 77         ans=max(ans,b[l[i]+id-1]+add[i]);
 78     }
 79     return ans;
 80 }
 81 int main()
 82 {
 83  //  freopen("hqx.in","r",stdin);
 84 // cout<<lower_bound(a,a+5,2)-a<<endl;
 85     scanf("%d",&n);
 86     for(int i=1; i<=n; i++)
 87     {
 88         scanf("%lld",&a[i]);
 89         b[i]=a[i];
 90     }
 91     buildblock();
 92     ll op,st,ed;
 93     ll val;
 94     while(n--)
 95     {
 96         scanf("%lld %lld %lld %lld",&op,&st,&ed,&val);
 97         if(op==0)
 98         {
 99             update(st,ed,val);
100         }
101         else if(op==1)
102         {
103             ll tmp=ask(st,ed,val);
104             printf("%lld\n",tmp==-inf?-1:tmp);
105         }
106     }
107     return 0;
108 }

原文地址:https://www.cnblogs.com/letlifestop/p/10465946.html

时间: 2024-11-09 20:39:45

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

Loj 6279. 数列分块入门 3

题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的前驱(比其小的最大元素). 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 iii 个数字为 aia_iai?,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l, r][l,r] 的之间的数字

loj 6278 6279 数列分块入门 2 3

参考:「分块」数列分块入门1 – 9 by hzwer 2 Description 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,询问区间内小于某个值\(x\)的元素个数. 思路 每个块内保持升序排列. 则块外暴力统计,块内二分查找分界点. 一些注意点,如: 要记录下标: 块外暴力修改完之后需要再排序: 在块内二分查找的值是\(c-tag[i]\)而非\(c\). Code #include <bits/stdc++.h> #define maxn 50010 #def

#6283. 数列分块入门 7(区间乘法,区间加法,单点询问)

题目链接:https://loj.ac/problem/6283 题目大意:中文题目 具体思路:和线段树的思路相同,注意lazy的下放,对于不完整的区间,我们需要先更新数组a的值,然后再对数组a进行操作.对于完整的操作,我们要注意优先级,如果原来是a*b+c的话,我们要对这个区间乘以e的话,就表示成a*(b*e)+c*e. AC代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 const

LibreOJ6279. 数列分块入门 3 题解

题目链接:https://loj.ac/problem/6279 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其小的最大元素). 输入格式 第一行输入一个数字 \(n\). 第二行输入 \(n\) 个数字,第 \(i\) 个数字为 \(a_i\),以空格隔开. 接下来输入 \(n\) 行询问,每行输入四个数字 \(opt\).\(l\).\(r\).\(c\),以空格隔开. 若 \(opt=0\),表示将位于

LOJ6277~6285 数列分块入门

Portals 分块需注意的问题 数组大小应为\(N+\sqrt N\),因为最后一个块可能会超出\(N\)的范围.改成记录\(blk,fr,to\)就不用担心这个了 当操作的区间在一个块内时,要特判成暴力修改. 要清楚什么时候应该+tag[t] 最后一个块是越界的,注意是否有影响 数列分块入门 1 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. //数列分块入门 1 #include <cstdio> #include <cmath> inlin

LOJ#6278. 数列分块入门 2

内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,询问区间内小于某个值 xxx 的元素个数. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,

LibreOJ 6278. 数列分块入门 2 题解

题目链接:https://loj.ac/problem/6278 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数. 输入格式 第一行输入一个数字 \(n\). 第二行输入 \(n\) 个数字,第 \(i\) 个数字为 \(a_i\),以空格隔开. 接下来输入 \(n\) 行询问,每行输入四个数字 \(opt\).\(l\).\(r\).\(c\),以空格隔开. 若 \(opt=0\),表示将位于 \([l,r]

「分块」数列分块入门2 by hzwer

题意:给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数. 注意细节!! 对于最后一块非整块,要特殊处理!!! /* loj6278 */ #include<bits/stdc++.h> using namespace std; #define N 50005 int pos[N],sta[505],end[505],a[N],fl[505],b[N],block,n;//a是原数组 b是每一个块内有序的数组 void modify(int l,int r,

数列分块入门

分块是 莫队 算法的前置知识,也是一种十分 暴力 的数据结构. 分块的核心思想是把要操作的数列 \(a_i\) 分成若干长度相等的"块":修改/查询时对于整一块都在指定区间 \([L,R]\) 内的块整体修改/查询,对于只有块的一部分在指定区间内的暴力修改/查询. 由于不需要操作/查询具有 区间加法 等性质,分块比线段树.树状数组.ST表等数据结构具有更加灵活的应用. 先来看一道例题 数列分块入门 4,简而言之,就是要求实现区间加法&区间查询:线段树可以很轻松地实现这两个操作,