数列分块入门 4

题目

给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,区间求和。

输入

第一行输入一个数字 nn。

第二行输入 nn 个数字,第 ii 个数字为 a_iai​,以空格隔开。

接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。

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

若 \mathrm{opt} = 1opt=1,表示询问位于 [l, r][l,r] 的所有数字的和 \bmod (c+1)mod(c+1)。

输出

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

样例

样例输入

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

样例输出

1
4

题解

当有修改时,对于完整的块,直接维护一个数组v记录整个块加过的数(每块共同的加数)与s记录每个块的和(不算共同加数),不完整的就直接暴力在原数组a上直接加,并且别忘了给s也加上。询问时,对于不完整的块,直接暴力加(别忘了共同加数),完整的块对于每个区间ans加上 (区间和 + 共同加数 * 大小)就可以了。

代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
#define LL long longint n, t, m;
LL a[MAXN], p[MAXN], v[500], s[500];
LL opt, l, r, c;void Add( int l, int r, int c ){if ( p[l] == p[r] ){for ( int i = l; i <= r; ++i ) a[i] += c, s[p[i]] += c;return;}for ( int i = l; p[l] == p[i]; ++i ) a[i] += c, s[p[i]] += c;for ( int i = r; p[r] == p[i]; --i ) a[i] += c, s[p[i]] += c;for ( int i = p[l] + 1; i < p[r]; ++i ) v[i] += c;
}LL query( int l, int r, LL c ){if ( p[l] == p[r] ){LL ans(0);for ( int i = l; i <= r; ++i ) ans += ( a[i] + v[p[i]] ) % c, ans %= c;return ans;}int ans(0);for ( int i = l; p[i] == p[l]; ++i ) ans += ( a[i] + v[p[i]] ) % c, ans %= c;for ( int i = r; p[i] == p[r]; --i ) ans += ( a[i] + v[p[i]] ) % c, ans %= c;for ( int i = p[l] + 1; i < p[r]; ++i ) ans += ( s[i] + v[i] * m ) % c, ans %= c;return ans % c;
}int main(){scanf( "%d", &n ); m = (int)sqrt(n);for ( int i = 1; i <= n; ++i )scanf( "%lld", &a[i] ), p[i] = ( i - 1 ) / m + 1, s[p[i]] += a[i];for ( int i = 1; i <= n; ++i ){scanf( "%d%lld%lld%lld", &opt, &l, &r, &c );if ( opt ) printf( "%lld\n", query( l, r, c + 1 ) );else Add( l, r, c );}
}

数列分块入门 5

题目描述
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间开方,区间求和。

输入格式
第一行输入一个数字 n。

第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。

接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。

若 opt=0,表示将位于 [l,r] 的之间的数字都开方,对于区间中的每个 ai(l<=i<=r),ai->|√ai|

若 opt=1,表示询问位于 [l,r] 的所有数字的和。

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

样例
样例输入

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

样例输出

6
2

【数据范围与提示】
对于 100% 的数据,1<=n<=50000,-2^31<=other,ans<=2^31-1。

题解

把已经不能再开方的块进行跳过,节约程序开方的时间。对块内每一个数都做开方运算,再把他们的和存进sum[]数组里面,再从左往右暴力循环左侧不完整块。\

代码

#include <bits/stdc++.h>
using namespace std;
int b[50005], a[50005], sum[255];
bool flag[255];
int len;int read() {int X = 0; bool flag = 1; char ch = getchar();while (ch < '0' || ch > '9') {if (ch == '-') flag = 0; ch = getchar();}while (ch >= '0' && ch <= '9') {X = (X << 1) + (X << 3) + ch - '0'; ch = getchar();}if (flag) return X;return ~ (X - 1);
}void write(int X) {//快速输出,同上if (X < 0) {putchar('-'); X = ~ (X - 1);}int s[50], top = 0;while (X) {s[++top] = X % 10; X /= 10;}if (!top) s[++top] = 0;while (top) putchar(s[top--] + '0');putchar('\n');return;
}void sol(int x) {if (flag[x]) return; //如果这个块被标记了,直接返回flag[x] = true;      //先把这个块标记sum[x] = 0;          //将sum[]数组初始化为零for (int i = (x - 1) * len + 1; i <= x * len; i++) { //循环块内每一个值a[i] = sqrt(a[i]), sum[x] += a[i]; //对块内每一个数都做开方运算,再把他们的和存进sum[]数组里面if (a[i] > 1) flag[x] = false;     //如果这一个值还大于1,也就是还能够进行开方,这个块就还能继续开放,把flag[]标记去除}return;
}void add(int l, int r) {for (int i = l; i <= (b[l] * len < r ? b[l] * len : r); i++) { //从左往右暴力循环左侧不完整块sum[b[l]] -= a[i];a[i] = sqrt(a[i]);sum[b[l]] += a[i];}if (b[l] != b[r]) //如果l和r不在同一块内for (int i = r; b[i] == b[r]; i--) { //同右往左暴力循环右侧不完整块//循环条件这里我原来一直写i == b[r]就错了,要注意,下面query()函数也是sum[b[r]] -= a[i];a[i] = sqrt(a[i]);sum[b[r]] += a[i];}for (int i = b[l] + 1; i <= b[r] - 1; i++) sol(i); //中间完整块使用sol()函数解决return;
}int query(int l, int r) { //查询函数int ans = 0;for (int i = l; i <= (b[l] * len < r ? b[l] * len : r); i++) ans += a[i];//左侧if (b[l] != b[r]) for (int i = r; b[i] == b[r]; i--) ans += a[i];//右侧for (int i = b[l] + 1; i <= b[r] - 1; i++) ans += sum[i];//中间return ans;
}int main() {int n;n = read();len = sqrt(n);for (int i = 1; i <= n; i++) a[i] = read();for (int i = 1; i <= n; i++) {b[i] = (i - 1) / len + 1;sum[b[i]] += a[i];}for (int i = 1; i <= n; i++) {bool opt; int l, r;opt = read(); l = read(); r = read(); read();opt ? write(query(l, r)) : add(l, r);//三目运算符,如果opt==1就add(),else就query()}return 0;
}

数列分块入门 6

题目

出一个长为 nn 的数列,以及 nn 个操作,操作涉及单点插入,单点询问,数据随机生成。

Input

第一行输入一个数字 nn 。 
第二行输入 nn 个数字,第 ii 个数字为 aiai,以空格隔开。 
接下来输入 nn 行询问,每行输入四个数字opt,l,r,copt,l,r,c,以空格隔开。 
若opt=0opt=0,表示在第 ll 个数字前插入数字rr(cc忽略)。 
若opt=1opt=1,表示询问 arar 的值(l和c忽略)。

Output

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

样例

样例输入

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

样例输出

2
3

题解

vector[]保存每一块的所有数。对于插入操作,直接找到对应的块,然后对这一块调用vector的insert。对于查询操作,直接把位置偏移过去,然后查询.

一旦发现块的大小>2n−−√>2n,那么把这个块一分为二.

代码

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;const int maxn = 1e5 + 10;int n, a[maxn];
int pos[maxn], len;
vector<int> b[maxn];void change(int l, int r, int c)
{int pt = 1, sum = b[1].size();while (sum < l) pt++, sum += b[pt].size();b[pt].insert(b[pt].begin() + l - (sum - b[pt].size()) - 1, r);
}int cal(int l, int r, int c)
{int pt = 1, sum = b[1].size();while (sum < r) pt++, sum += b[pt].size();return b[pt][r - (sum - b[pt].size()) - 1];
}void solve()
{scanf("%d", &n);len = sqrt(n);for (int i = 1; i <= n; i++){scanf("%d", &a[i]), pos[i] = (i - 1) / len + 1;b[pos[i]].push_back(a[i]);}for (int i = 1; i <= n; i++){int opt, l, r, c;scanf("%d%d%d%d", &opt, &l, &r, &c);if (opt == 0)change(l, r, c);elseprintf("%d\n", cal(l, r, c));}
}int main()
{freopen("Testin.txt", "r", stdin);//freopen("Testout.txt", "w", stdout);solve();return 0;
}

数列分块入门4-6题解相关推荐

  1. LOJ 数列分块入门6

    LOJ 数列分块入门6 题目: 题目 题解: 我都不懂这题为什么要用分块... ... 直接vector就好了... 但是如果有区间修改的话就不行了.所以这题是启示我们也可以动态分块.具体就是每次插入 ...

  2. 「分块系列」数列分块入门3 解题报告

    数列分块入门3 题意概括 区间加法,区间求前驱. 写在前面 这题的方法与分块2方法极其类似,建议自行解决. 正题 和上一题类似,但是二分不是用来计数的,而是用来求小于c的最大值的.然后对于不完整快,将 ...

  3. 【分块入门】LOJ 数列分块入门 1 - 9 (学习更新……)

    dl题解 _「分块」数列分块入门1 – 9 by hzwer LOJ #6277. 数列分块入门 1 题意:给出一个长为n的数列,以及n个操作,操作涉及区间加法,单点查值. 时间限制:100ms 分块 ...

  4. #6279. 数列分块入门 3(区间修改,查询权值前驱)

    #6279. 数列分块入门 3 这是使用hzwer建议的set写的分块代码,set自动排序,支持二分查找,但是常数较大,比我下面写的用vector实现的分块慢了三倍,空间大了10倍. #include ...

  5. LOJ #6280. 数列分块入门 4-分块(区间加法、区间求和)

    #6280. 数列分块入门 4 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 题目描述 给出一个长为 ...

  6. 数列分块入门(套题)(loj6277,loj6278,loj6279,loj6280,loj6281,loj6282,loj6283,loj6284,loj6285)

    前言 zjoi考差了,码一些分块题缓解一下心情 壹 数列分块入门 1[loj6277] 题目大意:区间加,单点查 直接分块,区间加时完全覆盖的块打tag,边界块暴力重构 块大小设为n\sqrt nn​ ...

  7. 数列分块入门 (1 ~ 7)

    分块 6277. 数列分块入门 1 分块思想 我们把每m个元素分成一块,所以我们总共的块数就是n/mn / mn/m块,一般情况下我们取m=nm = \sqrt{n}m=n​.对于区间加操作,我们可以 ...

  8. 「分块」数列分块入门1 – 9

    ACM模板 放暑假了,回归!!! 自己不会写暴力,而且好久没写代码了,于是学学分块的优雅暴力~ 「分块入门-LibreOJ」 「分块」数列分块入门1 – 9 by hzwer 数列简单分块问题实际上有 ...

  9. #6277. 数列分块入门 1

    题目链接:https://loj.ac/problem/6277 学习博客:http://hzwer.com/8053.html #6277. 数列分块入门 1 内存限制:256 MiB时间限制:10 ...

  10. #6279. 数列分块入门 3

    数列分块入门 3 #include<bits/stdc++.h> using namespace std; #define ll long long const int N=1000010 ...

最新文章

  1. PCB的地与机壳(连接大地)为什么用阻容连接?
  2. mysql 怎么查询结果补0_mysql查询连续时间数据——无数据补0
  3. WebDriver(C#)之十点使用心得
  4. 通过显示当前 python 程序占用的内存大小来比较生成器和迭代器(转载)
  5. ASP.NET 2.0个性化配置(profile)
  6. vue2.0项目部署到服务器_vue项目运行npm run build打包后如何发布到服务器?
  7. python 折线图_Python 编程一次画三种图:柱状图、散点图、折线图
  8. Django的学习(六)————templates过滤器、Django shell、admin
  9. Java 读取某个目录下所有文件、文件夹
  10. Fiddler抓取HTTPS最全(强)攻略!
  11. web网络图片查看器Android
  12. [转载] python2.7中模块学习- textwrap 文本包装和填充
  13. BZOJ 2431 [HAOI2009]逆序对数列 (dp)
  14. docker理念:不可变基础设施
  15. JasperReport:报表概述和模板制作
  16. Qt实战案例(13)——Qt的界面外观详细介绍
  17. 51单片机波特率计算c语言,8051单片机波特率计算公式(配套C语言例程
  18. 智能泊车技术及现状详解
  19. Bsphp验证系统,免费网络验证系统
  20. 云计算的概念与价值02技术与价值

热门文章

  1. 报童模型(1)-认识Newsvendor Model
  2. zabbix开启网页报警声音方法:网页也可以有报警声音(46)
  3. 商品分类,手机云进销存ERP门店零售批发仓库开单APP软件,文具五金服装鞋帽酒店烟酒饰品批发条码管理
  4. 信杂比公式_信噪比怎么计算
  5. 【C语言】流程图符号及流程图
  6. typedef的使用详解
  7. 中英文1:2等宽字体
  8. Android - 浅谈 Handler 机制
  9. 非线性光学近似计算机应用,浅谈非线性光学的发展及应用
  10. android ssh软件,优秀的 Android SSH 工具推荐