线段树可维护的基本信息

一、区间最值

1.单点替换:

 1 const int M=100001;
 2 LL a[M];
 3 LL MAX[M<<2];
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 void update(int rt){
 7     MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
 8 }
 9 void build(int l,int r,int rt){
10     if (l==r) {
11         MAX[rt]=a[l];
12         return;
13     }
14     int m=(l+r)>>1;
15     build(lson);
16     build(rson);
17     update(rt);
18 }
19 void modify(int l,int r,int rt,int p,int v){
20     if (l==r) {
21         MAX[rt]=v;
22         return;
23     }
24     int m=(l+r)>>1;
25     if (p<=m) modify(lson,p,v);
26     else modify(rson,p,v);
27     update(rt);
28 }
29
30 int query(int l,int r,int rt,int nowl,int nowr) {
31     if (nowl<=l && r<=nowr) return MAX[rt];
32     int ans=INT_MIN;
33     int m=(l+r)>>1;
34     if (nowl<=m) ans=max(ans,query(lson,nowl,nowr));
35     if (m<nowr) ans=max(ans,query(rson,nowl,nowr));
36     return ans;
37 }

2.区间增减:当一段区间整体增加(减少)某一个定值时,这段区间的最值也同时增大(减小)这个值,可参照区间和中区间增减的代码。

二、区间和

区间和是线段树可维护的最基本的信息,其他所有线段树可维护的序列信息,都是以区间和为模板建立的。

1.单点增减、单点替换:

 1 #define lson l,m,rt<<1
 2 #define rson m+1,r,rt<<1|1
 3 void update(int rt){
 4     sum[rt]=sum[rt<<1]+sum[rt<<1|1];//sum[rt]表示rt节点所包含的区间信息,此处为区间和
 5 }
 6 void build(int l,int r,int rt){ //构造线段树
 7     if (l==r) {
 8         sum[rt]=a[l];
 9         return;
10     }
11     int m=(l+r)>>1;
12     build(lson);
13     build(rson);
14     update(rt);
15 }
16 void modify(int l,int r,int rt,int p,LL v){ //将p位置修改为v
17     if (l==r) {
18         sum[rt]=v;//如果是将p位置的数+v,则此句应为sum[rt]+=v;
19         return;
20     }
21     int m=(l+r)>>1;
22     if (p<=m) modify(lson,p,v);
23     else modify(rson,p,v);
24     update(rt);
25 }
26
27 LL query(int l,int r,int rt,int nowl,int nowr) { //询问[nowl,nowr]的信息
28     if (nowl<=l && r<=nowr) return sum[rt];
29     LL ans=0;
30     int m=(l+r)>>1;
31     if (nowl<=m) ans+=query(lson,nowl,nowr);
32     if (m<nowr) ans+=query(rson,nowl,nowr);
33     return ans;
34 }

2.区间增减、区间替换:(测试:洛谷P3372)

 1 const int M=100001;
 2 LL a[M];
 3 LL sum[M<<2],lazy[M<<2];
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 void update(int rt){
 7     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 8 }
 9 void build(int l,int r,int rt){
10     lazy[rt]=0;//懒标记
11     if (l==r) {
12         sum[rt]=a[l];
13         return;
14     }
15     int m=(l+r)>>1;
16     build(lson);
17     build(rson);
18     update(rt);
19 }
20 void clean(int rt,int len){//懒标记下移
21     if(lazy[rt]){
22         lazy[rt<<1]+=lazy[rt];//若为区间替换则为“=”
23         lazy[rt<<1|1]+=lazy[rt];//同上
24         sum[rt<<1]+=lazy[rt]*(len-(len>>1));//同上
25         sum[rt<<1|1]+=lazy[rt]*(len>>1);//同上
26         lazy[rt]=0;
27     }
28 }
29 void modify(int l,int r,int rt,int nowl,int nowr,LL v){
30     int len=r-l+1;
31     if (nowl<=l&&r<=nowr) {
32         lazy[rt]+=v;//若为区间替换则为“=”
33         sum[rt]+=v*len;//同上
34         return;
35     }
36     clean(rt,len);//每次分治前需要下移懒标记,不分治就不下移
37     int m=(l+r)>>1;
38     if(nowl<=m)modify(lson,nowl,nowr,v);
39     if(m<nowr)modify(rson,nowl,nowr,v);
40     update(rt);
41 }
42 LL query(int l,int r,int rt,int nowl,int nowr) {
43     if (nowl<=l && r<=nowr) return sum[rt];
44     clean(rt,r-l+1);//同上
45     LL ans=0;
46     int m=(l+r)>>1;
47     if (nowl<=m) ans+=query(lson,nowl,nowr);
48     if (m<nowr) ans+=query(rson,nowl,nowr);
49     return ans;
50 }

3.区间加减乘混合(测试:洛谷P3373)

 1 typedef long long LL;
 2 const int M=100001;
 3 LL a[M];
 4 LL sum[M<<2],add[M<<2],c[M<<2];
 5 LL p;//模数
 6 #define lson l,m,rt<<1
 7 #define rson m+1,r,rt<<1|1
 8 void update(int rt){
 9     sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
10 }
11 void build(int l,int r,int rt){
12     add[rt]=0;c[rt]=1;//加法懒标记和乘法懒标记
13     if (l==r) {
14         sum[rt]=a[l];
15         return;
16     }
17     int m=(l+r)>>1;
18     build(lson);
19     build(rson);
20     update(rt);
21 }
22 void clean(int rt,int len){
23     if(c[rt]!=1){//先下移乘法标记,再下移加法标记
24         c[rt<<1]=c[rt<<1]*c[rt]%p;
25         c[rt<<1|1]=c[rt<<1|1]*c[rt]%p;
26         add[rt<<1]=add[rt<<1]*c[rt]%p;//加法标记也要乘上乘数
27         add[rt<<1|1]=add[rt<<1|1]*c[rt]%p;
28         sum[rt<<1]=sum[rt<<1]*c[rt]%p;
29         sum[rt<<1|1]=sum[rt<<1|1]*c[rt]%p;
30         c[rt]=1;
31     }
32     if(add[rt]){
33         add[rt<<1]=(add[rt<<1]+add[rt])%p;
34         add[rt<<1|1]=(add[rt<<1|1]+add[rt])%p;
35         sum[rt<<1]+=add[rt]*(len-(len>>1));sum[rt<<1]%=p;
36         sum[rt<<1|1]+=add[rt]*(len>>1);sum[rt<<1|1]%=p;
37         add[rt]=0;
38     }
39 }
40 void modify(int l,int r,int rt,int nowl,int nowr,LL v){//区间加法
41     int len=r-l+1;
42     if (nowl<=l&&r<=nowr) {
43         add[rt]=(add[rt]+v)%p;
44         sum[rt]=(sum[rt]+v*len%p)%p;
45         return;
46     }
47     clean(rt,len);
48     int m=(l+r)>>1;
49     if(nowl<=m)modify(lson,nowl,nowr,v);
50     if(m<nowr)modify(rson,nowl,nowr,v);
51     update(rt);
52 }
53 void modify_(int l,int r,int rt,int nowl,int nowr,LL v){//区间乘法
54     int len=r-l+1;
55     if(nowl<=l&&r<=nowr){
56         c[rt]=c[rt]*v%p;
57         add[rt]=add[rt]*v%p;
58         sum[rt]=sum[rt]*v%p;
59         return;
60     }
61     clean(rt,len);
62     int m=(l+r)>>1;
63     if(nowl<=m)modify_(lson,nowl,nowr,v);
64     if(m<nowr)modify_(rson,nowl,nowr,v);
65     update(rt);
66 }
67 LL query(int l,int r,int rt,int nowl,int nowr) {
68     if (nowl<=l && r<=nowr) return sum[rt];
69     clean(rt,r-l+1);
70     LL ans=0;
71     int m=(l+r)>>1;
72     if (nowl<=m) ans=(ans+query(lson,nowl,nowr))%p;
73     if (m<nowr) ans=(ans+query(rson,nowl,nowr))%p;
74     return ans;
75 }
时间: 2024-08-09 09:24:45

线段树可维护的基本信息的相关文章

线段树 --- (区间维护+逆推)

Buy Tickets Time Limit:4000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year was appro

hdu 1556 Color the ball(线段树区间维护+单点求值)

传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25511    Accepted Submission(s): 12393 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)

原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核

CodeForces 587 E.Duff as a Queen 线段树动态维护区间线性基

https://codeforces.com/contest/587/problem/E 一个序列, 1区间异或操作 2查询区间子集异或种类数 题解 解题思路大同小异,都是利用异或的性质进行转化,std和很多网友用的都是差分的思想,用两棵线段树 第一棵维护差分序列上的线性基,第二棵维护原序列的异或区间和,两者同时进行修改 考虑两个序列 $(a,b)(d,e)$,按照std的想法,应该是维护$(0 \^ a,a \^ b)(0 \^ d,d \^ e)$ 然后合并首尾变成$(0 \^ a,a \^

One Occurrence 线段树离线维护最小值

题意:一个长度为n的序列(记为A[i]),q次查询,每次输出查询区间内任意一个只出现一次的数字,没有则输出0. 思路:线段树结点存元素的位置和上一个相同元素出现过的位置(没有则为0,记为pos),线段树维护区间结点最小值,结点封装在pair里,第一key值为前一个相同元素出现的位置,先将查询存下来,对于1到n的每一个前缀[1,r],维护元素的最右边出现的pos值,例如1 1 2 3 2这个区间,他们的pos值分别是inf,1,inf,0,3.对于已经知道了[1,r],要得到[1,r+1],若A[

Codevs-4919 线段树练习4(区间加上一个值并求摸个区间整除k的数的个数,线段树+数组维护)

给你N个数,有两种操作 1:给区间[a,b]内的所有数都增加X 2:询问区间[a,b]能被7整除的个数 输入描述 Input Description 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数.如果第一个数是add,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是count,表示统计区间[a,b]能被7整除的个数 输出描述 Output Description 对于每个询问输出一行一个答案 样例输入 Sample

又是线段树(维护方差)

我们把方差公式展开 所以只需要维护一个区间平方和和区间和 当我们更新一个区间加时 所以pushdown就很好写了 具体见代码 #include<iostream> #include<cstdio> #include<cctype> #include<cmath> #define int long long using namespace std; #define ls(x) (x<<1) #define rs(x) (ls(x)|1) const

POJ3468(线段树区间维护)

#include<cstdio> #define lson n<<1,l,mid #define rson (n<<1)|1,mid+1,r #define gmid (a[n].l+a[n].r)>>1 using namespace std; const int MAX_N=100005; typedef long long LL; struct node{ int l,r; LL sum,lazy; }a[MAX_N<<2]; void P