线段树---分析 && 模板总结

线段树:(转)

数据结构专题---线段树:http://blog.csdn.net/metalseed/article/details/8039326

线段树总结:http://blog.csdn.net/shiqi_614/article/details/8228102

概述:

线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)!

性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍

Hdu 1066 敌兵布阵

·经典线段树应用:

Code:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4
 5 #define lson l , m , rt << 1
 6 #define rson m + 1 , r , rt << 1 | 1
 7 #define root 1 , n , 1
 8 #define LL long long
 9 #define maxn 50000*5
10
11 LL ad[maxn<<2];
12 LL su[maxn<<2];
13 void PushUp(int rt) {
14     su[rt] = su[rt<<1] + su[rt<<1|1];
15 }
16 void PushDown(int rt,int m) {
17     if (ad[rt]) {
18         ad[rt<<1] += ad[rt];
19         ad[rt<<1|1] += ad[rt];
20         su[rt<<1] += ad[rt] * (m - (m >> 1));
21         su[rt<<1|1] += ad[rt] * (m >> 1);
22         ad[rt] = 0;
23     }
24 }
25 void build(int l,int r,int rt) {
26     ad[rt] = 0;
27     if (l == r) {
28         scanf("%lld",&su[rt]);
29         return ;
30     }
31     int m = (l + r) >> 1;
32     build(lson);
33     build(rson);
34     PushUp(rt);
35 }
36 void update(int L,int R,int c,int l,int r,int rt) {
37     if (L <= l && r <= R) {
38         ad[rt] += c;
39         su[rt] += (LL)c * (r - l + 1);
40         return ;
41     }
42     PushDown(rt , r - l + 1);
43     int m = (l + r) >> 1;
44     if (L <= m) update(L , R , c , lson);
45     if (m < R) update(L , R , c , rson);
46     PushUp(rt);
47 }
48 LL query(int L,int R,int l,int r,int rt) {
49     if (L <= l && r <= R) {
50         return su[rt];
51     }
52     PushDown(rt , r - l + 1);
53     int m = (l + r) >> 1;
54     LL ret = 0;
55     if (L <= m) ret += query(L , R , lson);
56     if (m < R) ret += query(L , R , rson);
57     return ret;
58 }
59 int main() {
60     int n,number=1;
61     int T;
62     scanf("%d",&T);
63     while(T--){
64         printf("Case %d:\n",number++);
65         scanf("%d",&n);
66         build(root);
67         char op[20];
68         int a , b ;
69         while (scanf("%s",op) && op[0]!=‘E‘) {
70             if (op[0] == ‘Q‘) {
71                 scanf("%d%d",&a,&b);
72                 printf("%lld\n",query(a , b ,root));
73             } else {
74                 scanf("%d%d",&a,&b);
75                 if(op[0]==‘A‘)
76                     update(a , a , b , root);
77                 else
78                     update(a , a , -b , root);
79
80             }
81         }
82     }
83     return 0;
84 }
时间: 2024-10-14 03:29:21

线段树---分析 && 模板总结的相关文章

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

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

线段树lazy模板 luogu3372

线段树写得很少,这么基本的算法还是要会的-- #include<bits/stdc++.h> using namespace std; inline long long read() { long long x = 0, f = 1; char ch = getchar(); while (ch<'0' || ch>'9') { if (ch == '-') f = -1;ch = getchar(); } while (ch >= '0'&&ch <=

线段树1模板

传送门:线段树1 1 #include<cstdio> 2 3 const int MAXN = 200000*4; 4 typedef long long LL; 5 6 int n,m,p,u,v; 7 long long x,Segment_Tree[MAXN],Add[MAXN]; 8 9 template <typename Type> inline void Read(Type &in){ 10 Type f=1;char ch=getchar(); 11 fo

BZOJ4034 树上操作(树剖 线段树大模板)

BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #include<cstdio> #include<cstring> #define N 100001 using namespace std; struct ed{ int nxt,to; }e[N*2]; int ne=0,head[N]; long long int w0[N]; str

Pascal 线段树 lazy-tag 模板

先说下我的代码风格(很丑,勿喷) maxn表示最大空间的四倍 tree数组表示求和的线段树 delta表示增减的增量标记 sign表示覆盖的标记 delta,sign实际上都是lazy标志 pushdown表示标记下传 pushup表示标记上传(即求和,区间最值) update表示数据更新 线段树(segment tree)是一种特别有用的数据结构,我们在维护区间各种信息的时候它就是利器.可能读者嫌线段树代码太长,不想写,而树状数组代码简洁易于便携,但是我在这里想说,线段树能做到的很多东西树状数

二分索引树与线段树分析

二分索引树是一种树状数组,其全名为Binary Indexed Tree.二分索引树可以用作统计作用,用于计某段连续区间中的总和,并且允许我们动态变更区间中存储的值.二分索引树和线段树非常相似,二者都享有相同的O(log2(n))时间复杂度的更新操作和O(log2(n))时间复杂度的查询操作,区别在于二分索引树更加简洁高效,而线段树则较冗杂低效,原因在于对二分索引树的操作中是使用了计算机中整数存储的特性来进行加速,而线段树中由于使用的是比较操作,因此性能不及二分索引树.那么为什么我们不抛弃线段树

HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21978    Accepted Submission(s): 8714 Problem Description There are several anc

线段树--线段树【模板1】P3372

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式 输出包含若干行整数,即为所有操作2

【线段树】模板

struct NODE { int value; int left,right; } node[maxn]; int father[MAX]; void BuildTree(int i,int left,int right) { node[i].left = left; node[i].right = right; node[i].value = 0; if (left == right) { father[left] = i; return; } int mid = (left + right