线段树学习
admin
2024-05-15 16:17:48
0

线段树是用来维护区间信息的数据结构

洛谷P3372

区间加+区间查询

#includetypedef long long LL;
const int N = 100005;
LL tree[N * 4], lazy[N * 4];void push_down(int rt, int l, int r) {if (lazy[rt]) {int mid = l + ((r - l) >> 1);tree[rt << 1] += (mid - l + 1) * lazy[rt];lazy[rt << 1] += lazy[rt];tree[rt << 1 | 1] += (r - mid) * lazy[rt];lazy[rt << 1 | 1] += lazy[rt];lazy[rt] = 0;}
}void push_up(int rt) {tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}void build(int rt, int l, int r) {if (l == r) {scanf("%lld", &tree[rt]);return;}int mid = l + ((r - l) >> 1);build(rt << 1, l, mid);build(rt << 1 | 1, mid + 1, r);push_up(rt);
}//当前在rt,代表区间[l,r], 给[s,t]上每一个节点+val
void update(int rt, int l, int r, int s, int t, LL val) {if (s <= l && r <= t) {tree[rt] += (r - l + 1) * val;lazy[rt] += val;return;}if (t < l || r < s)return;push_down(rt, l, r);int mid = l + ((r - l) >> 1);if (s <= mid)update(rt << 1, l, mid, s, t, val);if (mid < t)update(rt << 1 | 1, mid + 1, r, s, t, val);push_up(rt);
}//当前在rt,代表区间[l,r], 查[s,t]
LL query(int rt, int l, int r, int s, int t) {if (s <= l && r <= t) {return tree[rt];}if (t < l || r < s)return 0;push_down(rt, l, r);int mid = l + ((r - l) >> 1);LL ans = 0;if (s <= mid)ans += query(rt << 1, l, mid, s, t);if (mid < t)ans += query(rt << 1 | 1, mid + 1, r, s, t);return ans;
}int main() {int n, m, q, x, y, k;scanf("%d%d", &n, &m);build(1, 1, n);while (m--) {scanf("%d%d%d", &q, &x, &y);if (q == 1) {scanf("%d", &k);update(1, 1, n, x, y, k);}else printf("%lld\n", query(1, 1, n, x, y));}return 0;
}

洛谷P3373

区间乘+区间加+区间查询

#include
typedef long long LL;
const int N = 100005;
int sum[N << 2], mul[N << 2], lazy[N << 2], p;void push_down(int rt, int l, int r) {int left_rt = rt << 1, right_rt = rt << 1 | 1, mid = l + ((r - l) >> 1);if (mul[rt] != 1) {mul[left_rt] = 1LL * mul[left_rt] * mul[rt] % p;mul[right_rt] = 1LL * mul[right_rt] * mul[rt] % p;lazy[left_rt] = 1LL * lazy[left_rt] * mul[rt] % p;lazy[right_rt] = 1LL * lazy[right_rt] * mul[rt] % p;sum[left_rt] = 1LL * sum[left_rt] * mul[rt] % p;sum[right_rt] = 1LL * sum[right_rt] * mul[rt] % p;mul[rt] = 1;}if (lazy[rt]) {sum[left_rt] = (sum[left_rt] + 1LL * lazy[rt] * (mid - l + 1) % p) % p;sum[right_rt] = (sum[right_rt] + 1LL * lazy[rt] * (r - mid) % p) % p;lazy[left_rt] = (lazy[left_rt] + lazy[rt]) % p;lazy[right_rt] = (lazy[right_rt] + lazy[rt]) % p;lazy[rt] = 0;}
}void push_up(int rt) {sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % p;
}void build(int rt, int l, int r) {mul[rt] = 1;if (l == r) {LL temp;scanf("%lld", &temp);sum[rt] = temp % p;return;}int mid = l + ((r - l) >> 1);build(rt << 1, l, mid);build(rt << 1 | 1, mid + 1, r);push_up(rt);
}void multiply(int rt, int l, int r, int s, int t, int val) {if (s <= l && r <= t) {sum[rt] = 1LL * sum[rt] * val % p;mul[rt] = 1LL * mul[rt] * val % p;lazy[rt] = 1LL * lazy[rt] * val % p;return;}if (t < l || r < s)return;push_down(rt, l, r);int mid = l + ((r - l) >> 1);if (s <= mid)multiply(rt << 1, l, mid, s, t, val);if (mid < t)multiply(rt << 1 | 1, mid + 1, r, s, t, val);push_up(rt);
}void add(int rt, int l, int r, int s, int t, int val) {if (s <= l && r <= t) {sum[rt] = (sum[rt] + 1LL * (r - l + 1) * val % p) % p;lazy[rt] = (lazy[rt] + val) % p;return;}if (t < l || r < s)return;push_down(rt, l, r);int mid = l + ((r - l) >> 1);if (s <= mid) add(rt << 1, l, mid, s, t, val);if (mid < t) add(rt << 1 | 1, mid + 1, r, s, t, val);push_up(rt);
}int query(int rt, int l, int r, int s, int t) {if (s <= l && r <= t) {return sum[rt];}if (t < l || r < s)return 0;push_down(rt, l, r);int mid = l + ((r - l) >> 1);int ans = 0;if (s <= mid) ans = (ans + query(rt << 1, l, mid, s, t)) % p;if (mid < t) ans = (ans + query(rt << 1 | 1, mid + 1, r, s, t)) % p;return ans;
}int main() {int n, m, q, x, y;LL k;scanf("%d%d%d", &n, &m, &p);build(1, 1, n);while (m--) {scanf("%d%d%d", &q, &x, &y);if (q == 3)printf("%d\n", query(1, 1, n, x, y));else {scanf("%lld", &k);k %= p;if (q == 1)multiply(1, 1, n, x, y, k);else add(1, 1, n, x, y, k);}}return 0;
}

poj2528

区间修改成一个值
这里数据量加大,使用离散化,但是普通的离散化会出问题
比如[1,10],[1,4],[6,10][1,10],[1,4],[6,10][1,10],[1,4],[6,10],离散化了是[1,4],[1,2],[3,4][1,4],[1,2],[3,4][1,4],[1,2],[3,4],然而[1,2],[3,4][1,2],[3,4][1,2],[3,4]就能把[1,4][1,4][1,4]全部覆盖了
所以如果两个数字之间差大于一就补一个数字,比如1,4,6,101,4,6,101,4,6,10,就补成1,2,4,5,6,7,101,2,4,5,6,7,101,2,4,5,6,7,10,离散化完了[1,7],[1,3],[5,7][1,7],[1,3],[5,7][1,7],[1,3],[5,7]

#include
#include
using namespace std;
const int N = 10005;
bool visit[N];
int id[N << 2], left[N], right[N];
int lazy[N << 4];
void push_down(int rt) {if (lazy[rt]) {lazy[rt << 1] = lazy[rt];lazy[rt << 1 | 1] = lazy[rt];lazy[rt] = 0;}
}
void update(int rt, int l, int r, int s, int t, int val) {if (s <= l && r <= t) {lazy[rt] = val;return;}if (t < l || r < s)return;push_down(rt);int mid = l + ((r - l) >> 1);if (s <= mid)update(rt << 1, l, mid, s, t, val);if (mid < t)update(rt << 1 | 1, mid + 1, r, s, t, val);
}int ans;
void query(int rt, int l, int r) {if (lazy[rt]) {if (!visit[lazy[rt]]) {visit[lazy[rt]] = true;++ans;}return;}if (l == r)return;int mid = l + ((r - l) >> 1);query(rt << 1, l, mid);query(rt << 1 | 1, mid + 1, r);
}int main() {int T, n, cnt;scanf("%d", &T);while (T--) {cnt = ans = 0;memset(lazy, 0, sizeof(lazy));memset(visit, false, sizeof(visit));scanf("%d", &n);for (int i = 0; i < n; ++i) {scanf("%d%d", &left[i], &right[i]);id[cnt++] = left[i];id[cnt++] = right[i];}sort(id, id + cnt);cnt = unique(id, id + cnt) - id;for (int i = cnt - 1; i > 1; --i) {if (id[i] > id[i - 1] + 1) {id[cnt++] = id[i - 1] + 1;}}sort(id, id + cnt);for (int i = 0; i < n; ++i) {int l = lower_bound(id, id + cnt, left[i]) - id;int r = lower_bound(id, id + cnt, right[i]) - id;update(1, 1, cnt, l + 1, r + 1, i + 1);}query(1, 1, cnt);printf("%d\n", ans);}return 0;
}

poj2828

单点修改

#include
const int N = 200005;
int lazy[N << 2], p[N], v[N], res[N];void push_up(int rt) {lazy[rt] = lazy[rt << 1] + lazy[rt << 1 | 1];
}void build(int rt, int l, int r) {if (l == r) {lazy[rt] = 1;return;}int mid = l + ((r - l) >> 1);build(rt << 1, l, mid);build(rt << 1 | 1, mid + 1, r);push_up(rt);
}int query(int rt, int l, int r, int val) {if (l == r) {lazy[rt] = 0;return l;}int mid = l + ((r - l) >> 1);int ans;if (lazy[rt << 1] >= val) ans = query(rt << 1, l, mid, val);else ans = query(rt << 1 | 1, mid + 1, r, val - lazy[rt << 1]);push_up(rt);return ans;
}int main() {int n;while (~scanf("%d", &n)) {build(1, 1, n);for (int i = 0; i < n; ++i) {scanf("%d%d", &p[i], &v[i]);}for (int i = n - 1; i >= 0; --i) {res[query(1, 1, n, p[i] + 1) - 1] = v[i];}for (int i = 0; i < n; ++i) {if (i > 0)printf(" ");printf("%d", res[i]);}printf("\n");}return 0;
}

poj1151

扫描线,按照y方向排序
对x离散化

记录区间的覆盖次数

#include
#include
using namespace std;
const int N = 205;
double sum[N << 2];//总长度
int flag[N << 2];//区间覆盖次数
double x[N];
class Line {
public:double x1, x2, y;int flag;Line(const double& x1 = 0, const double& x2 = 0, const double& y = 0, const int& flag = 1) :x1(x1), x2(x2), y(y), flag(flag) {}bool operator< (const Line& o)const {return y < o.y;}
}line[N];void push_up(int rt, int l, int r) {if (flag[rt]) {//区间至少被覆盖了一次sum[rt] = x[r + 1 - 1] - x[l - 1];}else if (l == r) {//一个点sum[rt] = 0;}else {sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];}
}void update(int rt, int l, int r, int s, int t, int val) {if (s <= l && r <= t) {flag[rt] += val;push_up(rt, l, r);return;}if (t < l || r < s)return;int mid = l + ((r - l) >> 1);if (s <= mid)update(rt << 1, l, mid, s, t, val);if (mid < t)update(rt << 1 | 1, mid + 1, r, s, t, val);push_up(rt, l, r);
}int main() {int n, t = 0;while (scanf("%d", &n), n) {memset(sum, 0, sizeof(sum));memset(flag, 0, sizeof(flag));int cnt = 0;for (int i = 0; i < n; ++i) {double x1, y1, x2, y2;scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);line[cnt] = Line(x1, x2, y1, 1);x[cnt++] = x1;line[cnt] = Line(x1, x2, y2, -1);x[cnt++] = x2;}sort(line, line + cnt);sort(x, x + cnt);int k = unique(x, x + cnt) - x;double ans = 0;for (int i = 0; i + 1 < cnt; ++i) {int x1 = lower_bound(x, x + k, line[i].x1) - x + 1;int x2 = lower_bound(x, x + k, line[i].x2) - x + 1;update(1, 1, k, x1, x2 - 1, line[i].flag);ans += sum[1] * (line[i + 1].y - line[i].y);}++t;printf("Test case #%d\nTotal explored area: %.2lf\n\n", t, ans);}return 0;
}

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...