线段树算是一种较为简单的中级数据结构了,线段树本身其实还是很简单的,就是一棵二叉树,每一个节点维护一块区间的信息,如果根节点是$[1,n]$,那么左儿子就是$[1,n/2]$,右儿子就是$[n/2+1,n]$,如此二分下去就是一棵线段树了,查找的时间复杂度是 $Oleft ( log_{2} N ight )$的,有图为证:(网上找的)
下面是某线段树模板题的代码:
#include <cstdio> #include <algorithm> using namespace std; typedef long long LL; static const int maxm=1e6+10; LL tree[maxm],lazy[maxm],A[maxm],left[maxm],right[maxm]; int n,m; void build(int num,int l,int r){ left[num]=l;right[num]=r; int mid=(l+r)>>1; if(l==r){ tree[num]=A[l]; return; } build(num<<1,l,mid); build(num<<1|1,mid+1,r); tree[num]=tree[num<<1]+tree[num<<1|1]; } void pushdown(int num){ if(lazy[num]){ int mid=(left[num]+right[num])>>1; tree[num<<1]+=(mid-left[num]+1)*lazy[num]; tree[num<<1|1]+=(right[num]-mid)*lazy[num]; lazy[num<<1]+=lazy[num]; lazy[num<<1|1]+=lazy[num]; lazy[num]=0; } } void update(int num,int l,int r,LL add){ if(left[num]>=l&&right[num]<=r){ tree[num]+=(right[num]-left[num]+1)*add; lazy[num]+=add; return; } if(left[num]>r||right[num]<l)return; pushdown(num); update(num<<1,l,r,add); update(num<<1|1,l,r,add); tree[num]=tree[num<<1]+tree[num<<1|1]; } LL Query(int num,int l,int r){ if(left[num]>=l&&right[num]<=r)return tree[num]; if(left[num]>r||right[num]<l) return 0; LL ret=0; pushdown(num); ret+=Query(num<<1,l,r); ret+=Query(num<<1|1,l,r); return ret; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&A[i]); build(1,1,n); for(int i=1;i<=m;i++){ int f,x,y;LL add; scanf("%d",&f); switch(f){ case 1:scanf("%d%d%lld",&x,&y,&add);update(1,x,y,add);break; case 2:scanf("%d%d",&x,&y);printf("%lld ",Query(1,x,y));break; default:printf("Orz %%%");break; } } return 0; }
以下是维护序列的代码:(滋瓷乘法运算)
1 #include <cstdio> 2 3 typedef long long LL; 4 5 static const int maxm=100005; 6 7 LL A[maxm],pls[maxm<<2],mul[maxm<<2],tr[maxm<<2]; 8 int left[maxm<<2],right[maxm<<2]; 9 int n,m; 10 LL MOD; 11 12 int build(int id,int l,int r){ 13 left[id]=l;right[id]=r;mul[id]=1; 14 if(l==r)return tr[id]=A[l]%MOD,0; 15 int mid=(l+r)>>1; 16 build(id<<1,l,mid); 17 build(id<<1|1,mid+1,r); 18 tr[id]=(tr[id<<1]+tr[id<<1|1])%MOD; 19 } 20 21 void pushdown(int id){ 22 int l=left[id];int r=right[id];int mid=(l+r)>>1; 23 pls[id<<1]=(pls[id<<1]*mul[id]%MOD+pls[id])%MOD; 24 pls[id<<1|1]=(pls[id<<1|1]*mul[id]%MOD+pls[id])%MOD; 25 mul[id<<1]=(mul[id]*mul[id<<1])%MOD; 26 mul[id<<1|1]=(mul[id]*mul[id<<1|1])%MOD; 27 tr[id<<1]=(tr[id<<1]*mul[id]%MOD+pls[id]*(mid-l+1)%MOD)%MOD; 28 tr[id<<1|1]=(tr[id<<1|1]*mul[id]%MOD+pls[id]*(r-mid)%MOD)%MOD; 29 mul[id]=1;pls[id]=0; 30 } 31 32 void modify(int id,int l,int r,int c,int opt){ 33 if(left[id]>=l&&right[id]<=r){ 34 if(opt==1){ 35 mul[id]=(mul[id]*c)%MOD; 36 pls[id]=(pls[id]*c)%MOD; 37 tr[id]=(tr[id]*c)%MOD; 38 }else if(opt==2){ 39 pls[id]=(pls[id]+c)%MOD; 40 tr[id]=(tr[id]+(LL)c*(right[id]-left[id]+1)%MOD)%MOD; 41 } 42 return ; 43 } 44 if(right[id]<l||left[id]>r)return ; 45 pushdown(id); 46 modify(id<<1,l,r,c,opt); 47 modify(id<<1|1,l,r,c,opt); 48 tr[id]=(tr[id<<1]+tr[id<<1|1])%MOD; 49 } 50 51 LL Query(int id,int l,int r){ 52 if(left[id]>=l&&right[id]<=r)return tr[id]%MOD; 53 if(left[id]>r||right[id]<l)return 0; 54 pushdown(id); 55 return (Query(id<<1,l,r)%MOD+Query(id<<1|1,l,r)%MOD)%MOD; 56 } 57 58 int main(){ 59 int opt,l,r,c; 60 scanf("%d%lld",&n,&MOD); 61 for(int i=1;i<=n;i++)scanf("%lld",&A[i]); 62 scanf("%d",&m); 63 64 build(1,1,n); 65 66 while(m--){ 67 scanf("%d",&opt); 68 if(opt!=3){ 69 scanf("%d%d%d",&l,&r,&c); 70 modify(1,l,r,c,opt); 71 } 72 else scanf("%d%d",&l,&r),printf("%lld ",Query(1,l,r)%MOD); 73 } 74 75 return 0; 76 }