线段树学习

news/2024/11/29 4:46:32/

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

洛谷P3372

区间加+区间查询

#include<cstdio>typedef 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<cstdio>
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<cstdio>
#include<algorithm>
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<cstdio>
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<cstdio>
#include<algorithm>
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;
}

http://www.ppmy.cn/news/18986.html

相关文章

计算机视觉OpenCv学习系列:第八部分、图像操作-4

第八部分、图像操作-4第一节、图像卷积操作1.图像卷积定义2.卷积函数3.代码练习与测试第二节、高斯模糊1.高斯模糊2.函数解释3.代码练习与测试第三节、像素重映射1.像素重映射定义2.重映射函数3.代码练习与测试学习参考第一节、图像卷积操作 1.图像卷积定义 卷积的基本原理&am…

cmake 04 使用 python 管理 cmake 工程

本文目标 使用 python 写一个管理 cmake 工程的 cli 程序 参考 Python CLI python Click 官网 Click 中文文档 python多文件打包.exe执行文件 argparse 文档 使用说明 详细说明 思路 使用 click 制作单独的命令, 比如 mcmake_inti,mcmake_built , 每一个命令都打包为…

深入剖析JVM垃圾收集器

文章目录前言1、新生代垃圾收集器1.1、Serial1.2、ParNew1.3、Parallel Scavenge2、老年代垃圾收集器2.1、Serial Old2.2、Parallel Old2.3、CMS&#xff08;Concurrent Mark Sweep&#xff09;3、全堆垃圾收集器3.1、Garbage First&#xff08;G1&#xff09;前言 参考资料&am…

开发人员必备的 15 个备忘单

随着网络编程技术的快速发展&#xff0c;我们必须学习很多新东西。有些语言和框架非常复杂&#xff0c;您可能记不住所有的语法或方法。备忘单是易于访问的笔记。当有人在过去目睹任何有帮助或有价值的事情时&#xff0c;包括我自己&#xff0c;我们都会做笔记。但是&#xff0…

java枚举类2023028

一个类的对象是有限而且固定的&#xff0c;比如季节类&#xff0c; 它只有4个对象&#xff1b;再比如行星类&#xff0c;目前只有8个对象。这种实例有限而且固定的类&#xff0c;在Java里被称为枚举类。在早期代码中&#xff0c;可能会直接使用简单的静态常量来表示枚&#xff…

C语言之程序结构和常量

2.1.1 C语言的发展及标准 C语言&#xff1a;一种通用的、面向过程的计算机程序设计语言&#xff08;第三代高级语言&#xff09;1972年&#xff0c;为了移植与开发UNIX操作系统&#xff0c;丹尼斯里奇在贝尔电话实验室设计开发了C语言为了利于C语言的全面推广&#xff0c;许多…

SelectPdf for .NET 22.0 Crack

SelectPdf for .NET 是一个专业的 PDF 库&#xff0c;可用于创建、编写、编辑、处理和读取 PDF 文件&#xff0c;而无需在 .NET 应用程序中使用任何外部依赖项。使用此 .NET PDF 库&#xff0c;您可以实现丰富的功能&#xff0c;从头开始创建 PDF 文件或完全通过 C#/VB.NET 处理…

AtCoder Regular Contest 154 题解

A - Swap Digit 给2个长度均为n的十进制数&#xff0c;你可以任意次交换2个数相同位置的数字&#xff0c;要求使它们乘积最小 让其中一个数最小&#xff0c;另一个数最大。 #include<bits/stdc.h> using namespace std; #define For(i,n) for(int i1;i<n;i) #defi…