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] 的之间的数字都加 ccc。

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

输出格式

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

样例

样例输入

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}1≤n≤100000,?231≤others、ans≤231?1 \mathrm{ans} \leq 2^{31}-1ans≤231?1。

思路: 同数列分块2,但是这里用set维护,时间复杂度O(n*sqrt(n)*logn)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3
 4 #define F(i,a,b) for(int i=a;i<=b;i++)
 5 #define D(i,a,b) for(int i=a;i>=b;i--)
 6 #define ms(i,a)  memset(a,i,sizeof(a))
 7 #define LL       long long
 8 #define st(x)    ((x-1)*B+1)
 9 #define ed(x)    min(x*B,n)
10 #define bl(x)    ((x-1)/B+1)
11
12 int inline read(){
13     int x=0,w=0; char c=getchar();
14     while (c<‘0‘ || c>‘9‘) w+=c==‘-‘,c=getchar();
15     while (c>=‘0‘ && c<=‘9‘) x=(x<<3)+(x<<1)+(c^48),c=getchar();
16     return w? -x: x;
17 }
18
19 int const maxn=100003;
20 LL  const inf=1LL<<50;
21
22 int n,B;
23 LL a[maxn],add[400];
24 multiset<LL> s[400];
25 multiset<LL> :: iterator p;
26
27 void update(int l,int r,LL z){
28     int x=bl(l);
29     int y=bl(r);
30     if(x==y){
31         F(i,l,r) {
32             p=s[x].find(a[i]);
33             s[x].erase(p);
34             s[x].insert(a[i]+z) ;
35             a[i]+=z;
36         }
37     }else {
38         F(i,l,ed(x)) {
39             p=s[x].find(a[i]);
40             s[x].erase(p);
41             s[x].insert(a[i]+z);
42             a[i]+=z;
43         }
44         F(i,st(y),r){
45             p=s[y].find(a[i]);
46             s[y].erase(p);
47             s[y].insert(a[i]+z);
48             a[i]+=z;
49         }
50         F(i,x+1,y-1) add[i]+=z;
51     }
52 }
53
54 LL query(int l,int r,LL z){
55     int x=bl(l);
56     int y=bl(r);
57     LL ans=-inf;
58     if(x==y){
59         F(i,l,r) if(a[i]+add[x]<z) ans=max(ans,a[i]+add[x]);
60     }else {
61         F(i,l,ed(x)) if(a[i]+add[x]<z) ans=max(ans,a[i]+add[x]);
62         F(i,st(y),r) if(a[i]+add[y]<z) ans=max(ans,a[i]+add[y]);
63         F(i,x+1,y-1) {
64             p=s[i].lower_bound(z-add[i]);
65             if(p!=s[i].begin()) ans=max(ans,*(--p)+add[i]);
66         }
67     }
68     return ans==-inf?  -1: ans;
69 }
70 int main(){
71     n=read(); B=(int)sqrt(n);
72     F(i,1,n) a[i]=read();
73     F(i,1,bl(n)) F(j,st(i),ed(i)) s[i].insert(a[j]);
74     F(i,1,n){
75         int x=read();
76         int l=read();
77         int r=read();
78         int c=read();
79         if(x==0) update(l,r,c);
80         else printf("%lld\n",query(l,r,c));
81     }
82     return 0;
83 }

原文地址:https://www.cnblogs.com/ZJXXCN/p/9703836.html

时间: 2024-07-31 08:32:14

Loj 6279. 数列分块入门 3的相关文章

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

LOJ#6284. 数列分块入门 8

#6284. 数列分块入门 8 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 1 测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间询问等于一个数 ccc 的元素,并将这个区间的所有元素改为 ccc. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入三个数字 ll

Loj 6277 数列分块入门 1

题目链接:https://loj.ac/problem/6277 题面: 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间加法,单点查值. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 iii 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=0\mathrm{opt} = 0opt=0,表示将位于 [l,r][l,

loj#6285 数列分块入门 9 ( 回 滚 )

题目 :  链接 :https://loj.ac/problem/6285 题意:给出一个长为 n的数列,以及 n个操作,操作涉及询问区间的最小众数. 思路:虽然这不是一道 回滚莫队题,就是 暴力分块 的题, 但是 还是 可以用回滚莫队 写滴,好像大部分题解都是 暴力分块. #include<bits/stdc++.h> #define LL long long #define ULL unsigned long long #define rep(i,j,k) for(int i=j;i<

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,

#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

LOJ#6281. 数列分块入门 5

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

LOJ#6282. 数列分块入门 6

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

LOJ#6283. 数列分块入门 7

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