线段树——模板

洛谷P3372

线段树支持区间修改和区间查询,以v变量表示当前一段区间的总值,tag为懒标记,记录修改操作,在查询子节点时,由父节点下传,记录修改值的大小,并在子节点加入懒标记

l和r分别表示当前节点所包含的最左区间端点和最右区间端点,ls和rs分别代表当前节点的左子树和右子树

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<math.h>
  6 #define ll long long
  7 using namespace std;
  8 
  9 const ll maxn=1e5+10;
 10 ll n,m;
 11 ll a[maxn];
 12 
 13 struct node
 14 {
 15     ll v,tag;//权值与懒标记
 16     ll l,r;//左右两个端点
 17     node *ls,*rs;//左右两个子树
 18     
 19     inline void maketag(ll w)//修改节点值,打懒标记
 20     {
 21         v+=(r-l+1)*w;
 22         tag+=w;
 23     }
 24     inline void pushup()//权值上传(由子节点更新父节点)
 25     {
 26         v=ls->v+rs->v;
 27     }
 28     inline void pushdown()//下传(由父节点更新子节点)
 29     {
 30         if(tag==0) return ;
 31         else
 32         {
 33             if(ls==NULL)//无左子树
 34             {
 35                 node(l,(l+r)>>1);//动态开点
 36             }
 37             if(rs==NULL)//无右子树
 38             {
 39                 node(((l+r)>>1)+1,r);//动态开点
 40             }
 41             ls->maketag(tag);
 42             rs->maketag(tag);
 43             tag=0;
 44         }
 45     }
 46     node(const ll L,const ll R)//建树
 47     {
 48         l=L,r=R;
 49         if(l==r)//当前节点为叶子结点,无左右子树
 50         {
 51             tag=0;
 52             v=a[l];
 53             ls=rs=NULL;
 54         }
 55         else
 56         {
 57             tag=0;
 58             ll M=(l+r)>>1;
 59             ls=new node(L,M);
 60             rs=new node(M+1,R);
 61             pushup();
 62         }
 63     }
 64     inline bool inrange(const ll L,const ll R)//在查询区间以内
 65     {
 66         return (L<=l)&&(r<=R);
 67     }
 68     inline bool outrange(const ll L,const ll R)//在查询区间以外
 69     {
 70         return (l>R)||(r<L);
 71     }
 72     inline void upd(const ll L,const ll R,const ll w)//区间修改
 73     {
 74         if(inrange(L,R))
 75         {
 76             maketag(w);
 77         }
 78         else if(!outrange(L,R))
 79         {
 80             pushdown();
 81             ls->upd(L,R,w);
 82             rs->upd(L,R,w);
 83             pushup();
 84         }
 85     }
 86     inline ll qry(const ll L,const ll R)//区间查询
 87     {
 88         if(inrange(L,R)) return v;
 89         if(outrange(L,R)) return 0;
 90         pushdown();
 91         return ls->qry(L,R)+rs->qry(L,R);
 92     }
 93 };
 94 
 95 int main(void)
 96 {
 97     scanf("%lld%lld",&n,&m);
 98     for(int i=1;i<=n;i++) scanf("%lld",a+i);
 99     node *rot=new node(1,n);//建树
100     
101     for(ll f,x,y,z;m;m--)
102     {
103         scanf("%lld",&f);
104         
105         if(f==1)
106         {
107             scanf("%lld%lld%lld",&x,&y,&z);
108             rot->upd(x,y,z);//更新操作
109         }
110         if(f==2)
111         {
112             scanf("%lld%lld",&x,&y);
113             printf("%lld\n",rot->qry(x,y));//查询操作
114         }
115     }
116     return 0;
117 }

 

posted @ 2020-07-05 14:35  雾隐  阅读(142)  评论(0编辑  收藏  举报