P3372 【模板】线段树 1

橙三吉。 提交于 2019-12-13 21:20:08

Miku

------------------------

线段是是一种非常重要的数据结构,尤其在暴力时候

-------------------------

线段树我觉得就是一个暴力的暴力的暴力数据结构,支持许多操作,比如说最大值,最小值,区间加,区间和等

------------------------

线段树的优化关键在于一个懒标记

------------------------

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 struct kk{
 6     int l,r;//每一个节点包含的左右区间 
 7     long long add,tql;//每一个节点的lazy和区间和 
 8 }t[10000005];
 9 long long n,m,a[10000005],p,x,y,pp;
10 void build(int x,int y,int z){
11     t[x].l=y; t[x].r=z;//这个点的控制的左右区间 
12     if(y==z){//一开始,只有叶节点赋值 
13         t[x].tql = a[y];
14         return ;
15     }
16     int midd =(y+z)>>1;//中间点,因为线段树就是从中间开始分裂的 
17     build(2*x,y,midd);
18     build(2*x+1,midd+1,z);
19     t[x].tql=max(t[x*2].tql+t[x*2+1].tql,(long long)0);//递归计算 
20 
21 }
22 void spr(int ooo){
23     if(t[ooo].add){
24         t[2*ooo].tql+=t[ooo].add*(t[2*ooo].r-t[2*ooo].l+1);//把这个点的实际值变成左右之和 
25         t[ooo*2+1].tql+=t[ooo].add*(t[ooo*2+1].r - t[ooo*2+1].l+1);//左右之和为加的值和区间节点数之和 
26         t[ooo*2].add+=t[ooo].add;
27         t[ooo*2+1].add+=t[ooo].add;//分发标记 
28         t[ooo].add =0; //分发完了,这没了 
29     }
30 }
31 void pluss(int oo, int ll,int rr,int kk)
32     if(ll <= t[oo].l && rr>=t[oo].r){//包含就直接加 
33         t[oo].tql+=(long long) kk*(t[oo].r - t[oo].l+1);//统计一下答案 
34         t[oo].add +=kk;//记上标记 
35         return ;
36     }
37     spr(oo);
38     int midd = (t[oo].l+t[oo].r)>>1; 
39     if(x<=midd) pluss(oo*2,x,y,kk);//分发标记 
40     if(y>midd) pluss(oo*2+1,x,y,kk);
41     t[oo].tql = max(t[oo<<1].tql+ t[oo*2+1].tql,(long long)0);//重新统计 
42 }
43 long long pr(int p,int x,int y){//查询 
44     if(x<=t[p].l&&y>=t[p].r) return t[p].tql;//包含直接返回 
45     spr(p);
46     int midd = t[p].l+t[p].r>>1;
47     long long ans =0;
48     if(x<=midd) ans+=pr(p<<1,x,y);//分摊查询 
49     if(y>midd) ans += pr(p*2+1,x,y);
50     return ans;
51 }
52 int main(){
53     cin>>n>>m;
54     for(int i=1;i<=n;++i) cin>>a[i];
55     build(1,1,n);
56     for(int i=1;i<=m;++i){
57         scanf("%lld",&p);
58         if(p==1){
59             scanf("%lld%lld%lld",&x,&y,&pp);
60             pluss(1,x,y,pp);
61         }
62         else {
63             scanf("%lld%lld",&x,&y);
64             cout<<pr(1,x,y)<<endl;
65         }
66     } 
67 }
Ac
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!