线段树简单操作模板复习(忘了。)

// 参考博客 https://www.cnblogs.com/TheRoadToTheGold/p/6254255.html#4175712

// 懒人标记: 表示当前结点区间值已经改变,但是下面的区间还没改变。每次询问到有懒人标记的结点时,在进一步询问他的子节点时,下放标记(下放的同时改变了子结点的值,并且赋予子节点懒人标记)// 因此 当将要查询对应区间时候 之前修改区间的操作在此时才进行 -- 因此叫懒人标记  1 #include<cstdio>
  2 using namespace std;
  3
  4 const int MAXN = 100000;
  5
  6 int ans;// 每次查询的结果
  7 struct node {
  8     int l, r, w, f;// 左端点下标,右端点下标,l~r各点权值和,"懒人"标记(在修改区间值时候,‘手动‘修改懒人标记)
  9 }tree[4*MAXN+1];
 10
 11 inline void build(int k, int ll, int rr) {// 建树
 12     tree[k].l = ll, tree[k].r = rr;
 13     if(tree[k].l == tree[k].r) {
 14         scanf("%d", &tree[k].w);
 15         return ;
 16     }
 17     int m = (ll + rr) / 2;
 18     build(k*2, ll, m);
 19     build(k*2+1, m+1, rr);
 20     tree[k].w = tree[k*2].w + tree[k*2+1].w;
 21 }
 22
 23 inline void down(int k) {// "懒"标记下传
 24     tree[k*2].f += tree[k].f;
 25     tree[k*2+1].f += tree[k].f;
 26     tree[k*2].w += tree[k].f * (tree[k*2].r - tree[k*2].l + 1);
 27     tree[k*2+1].w += tree[k].f * (tree[k*2+1].r - tree[k*2+1].l + 1);
 28     tree[k].f = 0;// 表明下传过了 不能重复下传(下次查询到此不再下传)
 29 }
 30
 31 inline void query_point(int k, int x) {// 单点查询(第x位置)
 32     if(tree[k].l == tree[k].r) {
 33         ans = tree[k].w;
 34         return ;
 35     }
 36     if(tree[k].f) down(k);
 37     int m = (tree[k].l + tree[k].r) / 2;
 38     if(x <= m) query_point(k*2, x);
 39     else query_point(k*2+1, x);
 40 }
 41
 42 inline void change_point(int k, int x, int v) {// 单点修改 x->x+v
 43     if(tree[k].l == tree[k].r) {
 44         tree[k].w += v;
 45         return ;
 46     }
 47     if(tree[k].f) down(k);
 48     int m = (tree[k].l + tree[k].r) / 2;
 49     if(x <= m) change_point(k*2, x, v);
 50     else change_point(k*2+1, x, v);
 51     tree[k].w = tree[k*2].w + tree[k*2+1].w;
 52 }
 53
 54 inline void query_interval(int k, int x, int y) {// 区间查询 x~y之和
 55     if(tree[k].l >= x && tree[k].r <= y) {
 56         ans += tree[k].w;
 57         return ;
 58     }
 59     if(tree[k].f) down(k);
 60     int m = (tree[k].l + tree[k].r) / 2;
 61     if(x <= m) query_interval(k*2, x, y);
 62     if(y > m) query_interval(k*2+1, x, y);
 63 }
 64
 65 inline void change_interval(int k, int x, int y, int v) {// 区间修改  x~y每个点+v
 66     if(tree[k].l >= x && tree[k].r <= y) {
 67         tree[k].w += (tree[k].r - tree[k].l + 1) * v;// 改变区间值
 68         tree[k].f += v;// 懒人标记
 69         return ;
 70     }
 71     if(tree[k].f) down(k);
 72     int m = (tree[k].l + tree[k].r) / 2;
 73     if(x <= m) change_interval(k*2, x, y, v);
 74     if(y > m) change_interval(k*2+1, x, y, v);
 75     tree[k].w += tree[k*2].w + tree[k*2+1].w;
 76 }
 77
 78 int main() {
 79     int n, m;
 80     scanf("%d", &n);
 81     build(1, 1, n);
 82     scanf("%d", &m);
 83     int p;
 84     int x, y, v;
 85     for(int i = 0; i != m; ++i) {
 86         scanf("%d", &p);
 87         ans = 0;
 88         if(p == 1) {
 89             scanf("%d", &x);
 90             query_point(1, x);// 单点查询 输出第k个数
 91             printf("%d\n", ans);
 92         }
 93         else if(p == 2) {
 94             scanf("%d%d", &x, &v);
 95             change_point(1, x, v);// 单点修改 x->x+v
 96         }
 97         else if(p == 3) {
 98             scanf("%d%d", &x, &y);
 99             query_interval(1, x, y);// 区间查询 x~y之和
100             printf("%d\n", ans);
101         }
102         else {
103             scanf("%d%d%d", &x, &y, &v);
104             change_interval(1, x, y, v);// 区间修改 x~y每个点+v
105         }
106     }
107     return 0;
108 }

原文地址:https://www.cnblogs.com/pupil-xj/p/11623774.html

时间: 2024-10-09 13:02:21

线段树简单操作模板复习(忘了。)的相关文章

线段树经典操作模板(单点更新,替换;区间更新,替换;区间求和求最值)

对于线段树的讲解此篇不再赘述,下面列出线段树应用中最常用的几种操作的代码.(具体题目未贴出,仅供有一定基础者参考代码风格) 另外,注意多组输入要写scanf("%d%d",&n,&m)!=EOF,线段树的题肯定要用c语言的输入输出,要使用字符数组,不用字符串,输入字符的时候要加getchar()吞噬空行.. (1)单点增减,区间求和: #include<iostream> #include<stdio.h> #include<string&

POJ 3468 A Simple Problem with Integers:线段树 简单操作 注意更新到区间而非叶节点

#include<cstdio> #include<iostream> using namespace std; #define Size 100000 struct Node { int L, R; long long Sum, Inc; int Mid() { return (L+R)/2; } }Tree[Size*3]; void CreatTree( int root, int L, int R )// 建区间树 { Tree[root].L = L; Tree[root

线段树 + 区间更新 + 模板 ---- poj 3468

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 59798   Accepted: 18237 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)

思路:本题因为是点修改,所以我们可以用线段树或者是树状数组了.线段树的基本操作我在我的代码中会具体体现,关键是要理解下面这幅图,具体的思想大家可以去看看其他的资料 线段树AC代码: #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define N 50005 int num

hdu1698(线段树区间替换模板)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698 题意: 第一行输入 t 表 t 组测试数据, 对于每组测试数据, 第一行输入一个 n , 表示钩子有 n 节, 编号为 1 ~ n, 每节钩子的初始价值为 1 , 接下来输入一个 q, 接着 q 行输入, 每行格式为 l, r, x, 表示讲区间 [l, r] 内的钩子价值变成 x , 求最终的总价值: 思路: 线段树区间替换模板 代码: 1 #include <iostream> 2 #

HDU 3016 Man Down 线段树+简单DP

囧,一开始看错题意,后来才发现人是垂直下落的,被附带链接里的Man Down游戏误导了. 那就变成了一个简单的DAG模型动态规划,随意搞就ok了 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <queu

敌兵布阵 (线段树简单模板题)

https://vjudge.net/contest/318019#problem C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向

2014多校10(1003)hdu4973(简单线段树区间操作)

A simple simulation problem. Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 679    Accepted Submission(s): 269 Problem Description There are n types of cells in the lab, numbered from 1 to n.

线段树lazytag优化模板

线段树嘛...很基本的一种数据结构啦 lazytag优化能不错的提高效率 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX=1000000; 4 struct pr { 5 int sum; 6 int lazy; 7 int left,right; 8 }tr[MAX+10]; 9 int n; 10 inline int ll(int k) {return 2*k;} 11 inline int rr(int