线段树
作者:互联网
大体长这个样子
特点:
任意两个节点,要么是包含关系,要么没有公共部分,不存在重叠或相交。
给定一个叶子节点p,从该节点到根节点的所有节点所代表的区间都包含p。
存储方式:静态数组存储,左孩子*2,右孩子*2+1本人不会指针,写不出指针写法
操作:
update:
利用子节点信息更新父节点信息
代码:
tree[k].sum=tree[lc].sum+tree[rc].sum;
pchange 点修改:
跟树状数组差不多,不多讲
1 void pchange(ll now,ll l,ll r,ll x,ll v) 2 { 3 if(l==r) 4 { 5 t[now].date+=v; 6 return; 7 } 8 ll mid=(l+r)>>1; 9 if(x<=mid) 10 { 11 pchange(t[now<<1],l,mid,x,v); 12 } 13 else 14 { 15 pchange(t[now<<1|1],mid+1,r,x,v); 16 } 17 update(now); 18 }View Code
query 区间查询:
如果当前节点所代表的区间被要查询的区间包含,则直接返回,否则,忽略;如果相交,那就二分,把查询任务交给子节点就行了
代码:
1 ll query(ll now,ll l,ll r,ll lr,ll rr) 2 { 3 if(lr<=l&&r<=rr) 4 { 5 return t[now].date; 6 } 7 ll mid=(l+r)>>1,ans=0; 8 if(lr<=mid) 9 { 10 ans+=query(t[now<<1],l,mid,lr,rr); 11 } 12 if(rr>mid) 13 { 14 ans+=query(t[now<<1|1],mid+1,r,lr,rr); 15 } 16 return ans; 17 }View Code
rchange 区间修改:
引入一个新变量delta,含义为已对当前点做过,但还没对当前点的子节点做过。(称之为懒标记)
每次修改、查询之前,都要下传懒标记,调用pushdown函数,下放标记。
pushdown函数代码:
1 ll pushout(int now,int x) 2 { 3 int l=t[now].l,r=t[now].r; 4 if(l==x&&r==x) 5 { 6 return t[now].date; 7 } 8 ll mid=(l+r)>>1; 9 pushdown(now,l,r,mid); 10 if(x<=mid) return pushout(t[now<<1],x); 11 else return pushout(t[now<<1|1],x); 12 }View Code
rchange函数代码:
1 void rchange(int now,int l,int r,int lrange,int rrange,ll v) 2 { 3 int cl=t[now<<1],cr=t[now<<1|1]; 4 if(lrange<=l&&r<=rrange) 5 { 6 delta[now]+=v; 7 t[now].date+=(r-l+1)*v; 8 return; 9 } 10 int mid=(l+r)>>1; 11 pushdown(now,l,r,mid); 12 if(lrange<=mid) 13 { 14 rchange(cl,l,mid,lrange,rrange,v); 15 } 16 if(rrange>mid) 17 { 18 rchange(cr,mid+1,r,lrange,rrange,v); 19 } 20 update(now); 21 }View Code
若区间修改后在进行区间查询,代码中也要加pushdown()
1 ll query(int p,int l,int r,int lrange,int rrange) 2 { 3 ll ans=0; 4 int mid=(l+r)>>1,cl=p<<1,cr=p<<1|1; 5 if(lrange<=l&&r<=rrange) 6 { 7 return t[p].date; 8 } 9 pushdown(p,l,r,mid); 10 if(lrange<=mid) 11 { 12 ans+=query(cl,l,mid,lrange,rrange); 13 } 14 if(rrange>mid) 15 { 16 ans+=query(cr,mid+1,r,lrange,rrange); 17 } 18 return ans; 19 }View Code
pushout单点查询:
1 ll pushout(int now,int x) 2 { 3 int l=t[now].l,r=t[now].r; 4 if(l==x&&r==x) 5 { 6 return t[now].date; 7 } 8 ll mid=(l+r)>>1; 9 pushdown(now,l,r,mid); 10 if(x<=mid) return pushout(t[now<<1],x); 11 else return pushout(t[now<<1|1],x); 12 }View Code
线段树的两个最重要的步骤——pushdown和update
所有的修改函数,最后都要update
大部分操作,开头都要pushdown
线段树相对于树状数组,功能更强大,在区间修改区间查询这一操作中,线段树比树状数组更好理解尽管代码长,但考场上可以临时发挥
以下代码为区间修改区间查询代码,各种树都可以套用以下代码 感谢respect_lowsmile(洛谷名)的分享!
代码:
1 #include<iostream> 2 #define int long long 3 using namespace std; 4 const int N=1e5+5; 5 struct node 6 { 7 int sum,lazy,len; 8 }; 9 node tree[N*4]; 10 int a[N]; 11 int n,m,x,y,k,pd; 12 void lazy(int k,int v) 13 { 14 tree[k].lazy+=v; 15 tree[k].sum+=tree[k].len*v; 16 } 17 void pushdown(int k) 18 { 19 if(tree[k].lazy==0) return ; 20 int lc=k<<1,rc=k<<1|1; 21 lazy(lc,tree[k].lazy); 22 lazy(rc,tree[k].lazy); 23 tree[k].lazy=0; 24 return ; 25 } 26 void build(int k,int l,int r) 27 { 28 tree[k].len=r-l+1; 29 if(l==r) 30 { 31 tree[k].sum=a[l]; 32 return ; 33 } 34 int mid,lc,rc; 35 mid=(l+r)>>1,lc=k<<1,rc=k<<1|1; 36 build(lc,l,mid); 37 build(rc,mid+1,r); 38 tree[k].sum=tree[lc].sum+tree[rc].sum; 39 return ; 40 } 41 void update(int k,int l,int r,int L,int R,int v) 42 { 43 if(l>=L&&r<=R) 44 return lazy(k,v); 45 pushdown(k); 46 int mid,lc,rc; 47 mid=(l+r)>>1,lc=k<<1,rc=k<<1|1; 48 if(L<=mid) 49 update(lc,l,mid,L,R,v); 50 if(R>mid) 51 update(rc,mid+1,r,L,R,v); 52 tree[k].sum=tree[lc].sum+tree[rc].sum; 53 } 54 int query(int k,int l,int r,int L,int R) 55 { 56 int res=0; 57 if(l>=L&&r<=R) 58 return tree[k].sum; 59 pushdown(k); 60 int mid,lc,rc; 61 mid=(l+r)>>1,lc=k<<1,rc=k<<1|1; 62 if(L<=mid) res+=query(lc,l,mid,L,R); 63 if(R>mid) res+=query(rc,mid+1,r,L,R); 64 return res; 65 } 66 signed main() 67 { 68 scanf("%lld %lld",&n,&m); 69 for(int i=1;i<=n;++i) 70 scanf("%lld",&a[i]); 71 build(1,1,n); 72 for(int i=1;i<=m;++i) 73 { 74 scanf("%lld",&pd); 75 if(pd==1) 76 { 77 scanf("%lld %lld %lld",&x,&y,&k); 78 update(1,1,n,x,y,k); 79 } 80 if(pd==2) 81 { 82 scanf("%lld %lld",&x,&y); 83 printf("%lld\n",query(1,1,n,x,y)); 84 } 85 } 86 return 0; 87 }View Code
如果对你有帮助,可以点一下赞吗?也可以关注一下呀QWQ,写的不好,dalao勿喷,谢谢!QAQ
标签:int,线段,tree,mid,pushdown,now,ll 来源: https://www.cnblogs.com/yifan0305/p/16428009.html