当前位置: 首页 > news >正文

243. 一个简单的整数问题2(线段树,懒标记,树状数组,《算法竞赛进阶指南》)

https://www.acwing.com/problem/content/244/

给定一个长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一:

  1. C l r d,表示把 A[l],A[l+1],…,A[r] 都加上 d。
  2. Q l r,表示询问数列中第 l∼r 个数的和。

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

输入格式

第一行两个整数 N,M。

第二行 N 个整数 A[i]。

接下来 M 行表示 M 条指令,每条指令的格式如题目描述所示。

输出格式

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

每个答案占一行。

数据范围

1≤N,M≤105
|d|≤10000
|A[i]|≤109

输入样例:
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
输出样例:
4
55
9
15

解析: 

线段数做法(懒标记):

进行区间操作时如果当前节点包含在区间内就直接更新,否则递归到子节点

区间修改需要用到懒标记,就是这段区间要加几先记录下来,要用到区间内部的信息时再下推到子节点

带懒标记的线段树可以在O(logn)的时间复杂度内完成各种区间操作

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
#include<unordered_set>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int INF = 0x3f3f3f3f;
const LL Mod = 1e9;
const int N = 1e5 + 10, M = 250 + 10, P = 110;
int n, m;
LL w[N];
struct Node {int l, r;LL sum, add;
}tr[N * 4];void pushup(int u) {tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}void pushdown(int u) {Node& root = tr[u], & l = tr[u << 1], & r = tr[u << 1 | 1];if (root.add) {l.sum +=(LL) (l.r - l.l + 1) * root.add, l.add += root.add;r.sum += (LL)(r.r - r.l + 1) * root.add, r.add += root.add;root.add = 0;}
}void build(int u, int l, int r) {if (l == r) {tr[u] = { l,l,w[l],0 };}else {tr[u] = { l,r };int mid = l + r >> 1;build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);pushup(u);}
}void modify(int u, int l, int r, int d) {if (tr[u].l >= l && tr[u].r <= r) {tr[u].sum += (tr[u].r - tr[u].l + 1) * d;tr[u].add += d;}else {pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid)modify(u << 1, l, r, d);if (r > mid) modify(u << 1 | 1, l, r, d);pushup(u);}
}LL query(int u, int l, int r) {if (tr[u].l >= l && tr[u].r <= r) {return tr[u].sum;}else {pushdown(u);int mid = tr[u].l + tr[u].r >> 1;LL ret = 0;if (l <= mid)ret += query(u << 1, l, r);if (r > mid)ret += query(u << 1 | 1, l, r);pushup(u);return ret;}
}int main() {cin >> n >> m;for (int i = 1; i <= n; i++) {scanf("%lld", &w[i]);}build(1, 1, n);char op[2];int l, r, d;while (m--) {scanf("%s", op);if (op[0] == 'C') {scanf("%d%d%d", &l, &r, &d);modify(1, l, r, d);}else {scanf("%d%d", &l, &r);printf("%lld\n", query(1, l, r));}}return 0;
}

 树状数组:

算前x个数的和时,差分后的第i(0<i<=x)个数加了x-i+1次

再定义一个数组B,B[i]=(A[i]-A[i-1])*i,c2为B的树状数组

求前缀和时返回c1[i]*(x+1)-c2[i]

神奇的事情出现了:

c1[i]*(x+1)中i往前lowbit(i)个数都被加了x+1次,

c2[i]中i往前lowbit(i)个数分别被加了下标次,

下标为j的数正好会被加x-j+1次

 

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
#include<unordered_set>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int INF = 0x3f3f3f3f;
const LL Mod = 1e9;
const int N = 1e5 + 10, M = 250 + 10, P = 110;
int n, m;
int a[N];
LL tr1[N], tr2[N];int lowbit(int x) {return x & -x;
}void add(LL tr[], int x, LL d) {for (int i = x; i <= n; i += lowbit(i))tr[i] += d;
}LL sum(LL tr[], int x) {LL ret = 0;for (int i = x; i; i -= lowbit(i))ret += tr[i];return ret;
}LL pre_sum(int x) {return sum(tr1, x) * (x + 1) - sum(tr2, x);
}int main() {cin >> n >> m;for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);}for (int i = 1; i <= n; i++) {add(tr1, i,(LL) a[i] - a[i - 1]);add(tr2, i, (LL)i * (a[i] - a[i - 1]));}while (m--) {char op[2];scanf("%s", op);if (op[0] == 'C') {int l, r, d;scanf("%d%d%d", &l, &r, &d);add(tr1, l, (LL) d),add(tr1,r+1,(LL)(-d));add(tr2, l, (LL) l* d),add(tr2, r + 1, (LL)(r + 1) *(-d));}else {int l, r;scanf("%d%d", &l, &r);printf("%lld\n", pre_sum(r)-pre_sum(l-1));}}return 0;
}

相关文章:

  • MoCo 算法阅读记录
  • Linux:自动化构建 - make
  • 全国水科技大会 免费征集《水环境治理减污降碳协同增效示范案例》
  • 使用阿里云试用Elasticsearch学习:2.1 深入搜索——结构化搜索
  • 解决前端笔记本电脑屏幕显示缩放比例125%、150%对页面大小的影响问题
  • Vite 项目中环境变量的配置和使用
  • 如何判断服务器的线路
  • 【通过虚拟现实:让我们对危险更敏感】
  • Win11 使用 WSL2 安装 linux 子系统 ubuntu
  • 虚幻引擎启动报错记录
  • 如何使用 React 构建跑马灯组件
  • 6种xinput1_3.dll丢失的解决办法,并探讨xinput1_3.dll丢失的原因及其属性。
  • Harmony鸿蒙南向驱动开发-MIPI DSI
  • HTTP与HTTPS:深度解析两种网络协议的工作原理、安全机制、性能影响与现代Web应用中的重要角色
  • Spring Boot 整合 Apache Phoenix 进行 HBase 数据操作指南
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 03Go 类型总结
  • Android交互
  • CODING 缺陷管理功能正式开始公测
  • django开发-定时任务的使用
  • docker容器内的网络抓包
  • emacs初体验
  • ES6语法详解(一)
  • gulp 教程
  • Javascript设计模式学习之Observer(观察者)模式
  • React Native移动开发实战-3-实现页面间的数据传递
  • RxJS: 简单入门
  • SpringBoot 实战 (三) | 配置文件详解
  • Theano - 导数
  • TypeScript迭代器
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 力扣(LeetCode)357
  • 排序算法之--选择排序
  • 深入浅出webpack学习(1)--核心概念
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • ​马来语翻译中文去哪比较好?
  • ![CDATA[ ]] 是什么东东
  • #14vue3生成表单并跳转到外部地址的方式
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #微信小程序:微信小程序常见的配置传值
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (145)光线追踪距离场柔和阴影
  • (4)事件处理——(7)简单事件(Simple events)
  • (libusb) usb口自动刷新
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (转)linux 命令大全
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...