ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线段树(区间查询,区间修改)——标记永久化版

2019-10-21 20:04:55  阅读:248  来源: 互联网

标签:ch 线段 add long seg 永久化 区间 now


传送门:https://www.luogu.org/problem/P3372

为了不下传add的标记,改为在询问的过程当中计算每个遇到的节点对当前询问的影响。而为了保证询问的复杂度,子节点的影响需要在修改操作时计算好。因此实际上,add的值表示这个区间共同加上的值,seg表示这个区间内除了add之外其它数的值的和。需要注意,区间的add值可能有一部分在祖先节点上,这在递归时累加即可。

 1 #include<bits/stdc++.h> 
 2 using namespace std;
 3 long long n,m;
 4 long long num[500009]; 
 5 long long seg[500009];//线段树上除了add之外的值 
 6 long long add[500009];//当前区间共同加上的值 
 7 inline long long read()
 8 {
 9     long long x=0,f=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
12     return x*f;
13 }
14 inline long long ls(long long x){return x<<1;}//左儿子 
15 inline long long rs(long long x){return x<<1|1;}//右儿子 
16 void build(long long now/*现在所在的节点*/,long long l,long long r/*它所在的原数列区间*/)
17 {
18     if(l==r)
19     {
20         seg[now]=num[l];
21         return;
22     }
23     long long mid=(l+r)>>1;
24     build(ls(now),l,mid);              //建立左儿子 
25     build(rs(now),mid+1,r);            //建立右儿子 
26     seg[now]=seg[ls(now)]+seg[rs(now)];//当前节点为其左右儿子的值之和 
27 }
28 void modify(long long now/*当前节点*/,long long l,long long r/* 当前区间[l,r] */,long long x,long long y,long long v)//给定区间[x,y]所有数加上v 
29 {
30     if(x<=l&&y>=r)/*如果给定区间包含当前区间就更新*/
31     {
32         add[now]+=v;/*加上这个区间共同的值*/
33         return;
34     }
35     seg[now]+=(min(r,y)-max(l,x)+1)*v;//计算子节点对当前节点的影响 
36     long long mid=(l+r)>>1;
37     if(x<=mid)modify(ls(now),l,mid,x,y,v);
38     if(mid<y)modify(rs(now),mid+1,r,x,y,v);
39 }
40 long long query(long long now,long long l,long long r,long long x,long long y)//询问区间[x,y]的和 
41 {
42     if(l>=x&&r<=y)return seg[now]+(r-l+1)*add[now];//加上这个区间的应当加上的add的值 
43     long long mid=(l+r)>>1;
44     long long res=(min(r,y)-max(l,x)+1)*add[now];  //计算标记的影响 
45     if(x<=mid)res+=query(ls(now),l,mid,x,y);       //计算左节点的贡献 
46     if(mid<y)res+=query(rs(now),mid+1,r,x,y);      //计算右节点的贡献 
47     return res;
48 }
49 int main()
50 {
51     n=read(),m=read();
52     for(long long i=1;i<=n;i++)
53     {
54         num[i]=read();
55     }
56     build(1,1,n);//建立线段树 
57     for(int i=1;i<=m;i++)
58     {
59         int pan=read();
60         if(pan==1)
61         {
62             int a=read(),b=read(),c=read();
63             modify(1,1,n,a,b,c);
64         }
65         if(pan==2)
66         {
67             long long a=read(),b=read();
68             cout<<query(1,1,n,a,b)<<endl;
69         }
70     }
71 }

 

标签:ch,线段,add,long,seg,永久化,区间,now
来源: https://www.cnblogs.com/1129-tangqiyuan/p/11715636.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有