线段树模板+详解

线段树

是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区
间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,
(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子
节点数目为N,即整个线段区间的长度。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂
度为O(logN) 。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

模板一:

//单点替换、单点增减、区间求和、区间最值
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 222222;
int MAX[maxn<<2];
int MIN[maxn<<2];
int SUM[maxn<<2];
int max(int a,int b){if(a>b)return a;else return b;}
int min(int a,int b){if(a<b)return a;else return b;}
void PushUP(int rt)
{
MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
MIN[rt] = min(MIN[rt<<1] , MIN[rt<<1|1]);
SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
}
void build(int l,int r,int rt) {
if (l == r)
{ 
scanf("%d",&MAX[rt]);
MIN[rt] = MAX[rt];
SUM[rt] = MAX[rt];
//printf("mi = %d\n",MIN[rt]);
// printf("ma = %d\n",MAX[rt]);
return ;
} 
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUP(rt);
} 
void update(int p,int tihuan,int l,int r,int rt)
{
if (l == r) {
MAX[rt] = tihuan;
MIN[rt] = tihuan;
SUM[rt] = tihuan;
return ;
} 
int m = (l + r) >> 1;
if (p <= m) update(p , tihuan ,lson);
else update(p , tihuan , rson);
PushUP(rt);
} 
void update1(int p,int add,int l,int r,int rt)
{
if (l == r) {
SUM[rt] = SUM[rt] + add;
return ;
} 
int m = (l + r) >> 1;
if (p <= m) update1(p , add ,lson);
else update1(p , add , rson);
PushUP(rt);
} 
int query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return MAX[rt];
} 
int m = (l + r) >> 1;
int ret = -1;
if (L <= m) ret = max(ret , query(L , R , lson));
if (R > m) ret = max(ret , query(L , R , rson));
return ret;
} 
int query1(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return MIN[rt];
} 
int m = (l + r) >> 1;
int ret = 99999;
if (L <= m) ret = min(ret , query1(L , R , lson));
if (R > m) ret = min(ret , query1(L , R , rson));
return ret;
} 
int queryhe(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return SUM[rt];
} 
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += queryhe(L , R , lson);
if (R > m) ret += queryhe(L , R , rson);
return ret;
} 
int main()
{
int n , m;
while (~scanf("%d%d",&n,&m))
{
build(1 , n , 1);
while (m --) {
char op[2];
int a , b;
scanf("%s%d%d",op,&a,&b);
if (op[0] == 'Q') //区间求最大
{
/* for(int i = 1;i<=10;i++)
printf("%d ",MAX[i]);
puts("");*/
printf("%d\n",query(a , b , 1 , n , 1));
} 
else if(op[0]=='U') //单点替换
update(a , b , 1 , n , 1);
else if(op[0]=='M')//区间求最小
{
/*for(int i = 1;i<=10;i++)
printf("%d ",MIN[i]);
puts("");*/
printf("%d\n",query1(a , b , 1 , n , 1));
} 
else if(op[0]=='H')//区间求和
{
printf("%d\n",queryhe(a , b , 1 , n , 1));
} 
else if(op[0]=='S')//单点增加
{
scanf("%d%d",&a,&b);
update1(a , b , 1 , n , 1);
}
else if(op[0]=='E')//单点减少
{
scanf("%d%d",&a,&b);
update1(a , -b , 1 , n , 1);
}
}
} 
return 0;
}

模板二:

//区间替换
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL long long
const int maxn = 100100;
using namespace std;
int lazy[maxn<<2];
int sum[maxn<<2];
void PushUp(int rt)//由左孩子、右孩子向上更新父节点
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
} 
void PushDown(int rt,int m) //向下更新
{
if (lazy[rt]) //懒惰标记
{
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
sum[rt<<1] = (m - (m >> 1)) * lazy[rt];
sum[rt<<1|1] = ((m >> 1)) * lazy[rt];
lazy[rt] = 0;
}
} 
void build(int l,int r,int rt)//建树
{
lazy[rt] = 0;
if (l== r)
{
scanf("%d",&sum[rt]);
return ;
} 
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
} 
void update(int L,int R,int c,int l,int r,int rt)//更新
{
//if(L>l||R>r) return;
if (L <= l && r <= R)
{
lazy[rt] = c;
sum[rt] = c * (r - l + 1);
//printf("%d %d %d %d %d\n", rt, sum[rt], c, l, r);
return ;
} 
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L , R , c , lson);
if (R > m) update(L , R , c , rson);
PushUp(rt);
} 
LL query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
//printf("%d\n", sum[rt]);
return sum[rt];
} 
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
LL ret = 0;
if (L <= m) ret += query(L , R , lson);
if (m < R) ret += query(L , R , rson);
return ret;
} 
int main()
{
int n , m;
char str[5];
while(scanf("%d%d",&n,&m))
{
build(1 , n , 1);
while (m--)
{
scanf("%s",str);
int a , b , c;
if(str[0]=='T')
{
scanf("%d%d%d",&a,&b,&c);
update(a , b , c , 1 , n , 1);
} 
else if(str[0]=='Q')
{
scanf("%d%d",&a,&b);
cout<<query(a,b,1,n,1)<<endl;
}
}
} 
return 0;
}

模板三:

//区间增减
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL __int64
const int maxn = 100100;
using namespace std;
LL lazy[maxn<<2];
LL sum[maxn<<2];
void putup(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void putdown(int rt,int m)
{
if (lazy[rt])
{
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt] * (m - (m >> 1));
sum[rt<<1|1] += lazy[rt] * (m >> 1);
lazy[rt] = 0;
}
} 
void build(int l,int r,int rt) {
lazy[rt] = 0;
if (l == r)
{
scanf("%I64d",&sum[rt]);
return ;
} 
int m = (l + r) >> 1;
build(lson);
build(rson);
putup(rt);
} 
void update(int L,int R,int c,int l,int r,int rt)
{
if (L <= l && r <= R)
{
lazy[rt] += c;
sum[rt] += (LL)c * (r - l + 1);
return ;
} 
putdown(rt , r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L , R , c , lson);
if (m < R) update(L , R , c , rson);
putup(rt);
} 
LL query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return sum[rt];
} 
putdown(rt , r - l + 1);
int m = (l + r) >> 1;
LL ret = 0;
if (L <= m) ret += query(L , R , lson);
if (m < R) ret += query(L , R , rson);
return ret;
} 
int main()
{
int n , m;int a , b , c;
char str[5];
scanf("%d%d",&n,&m);
build(1 , n , 1);
while (m--)
{
scanf("%s",str);
if (str[0] == 'Q')
{
scanf("%d%d",&a,&b);
printf("%I64d\n",query(a , b , 1 , n , 1));
} 
else if(str[0]=='C')
{
scanf("%d%d%d",&a,&b,&c);
update(a , b , c , 1 , n , 1);
}
} 
return 0;
}

(PS:什么都不会的同学看看这个QAQ==)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Usher_Ou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值