对于在线段树上修改整段区间的理解

第一题

HDU1698http://acm.hdu.edu.cn/showproblem.php?pid=1698

这是在区间上进行整段的修改操作,我们就用to[]数组代表修改的lazy标记

记住在构建树和在change函数中自顶向下更新的时候,一定要注意重新回去更新上层的节点,所以末尾需加上update(cur)

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 #define N 100005
 5 int sum[4*N],to[4*N];
 6
 7 void update(int x)
 8 {
 9     sum[x]=sum[x<<1]+sum[x<<1|1];
10 }
11 void build(int cur,int x,int y)
12 {
13     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
14     to[cur]=0;
15     if(x==y){
16         sum[cur]=1;
17         return;
18     }
19     build(ls,x,mid);
20     build(rs,mid+1,y);
21     update(cur);
22 }
23 void pushdown(int cur,int x,int y)
24 {
25     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
26     if(to[cur]!=0){
27         to[ls]=to[rs]=to[cur];
28         sum[ls]=(mid-x+1)*to[cur];
29         sum[rs]=(y-mid)*to[cur];
30         to[cur]=0;
31     }
32 }
33 void change(int cur,int x,int y,int s,int t,int v)
34 {
35     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
36     if(x>=s&&y<=t){
37         sum[cur]=(y-x+1)*v;
38         to[cur]=v;
39         return;
40     }
41     pushdown(cur,x,y);
42     if(mid>=s) change(ls,x,mid,s,t,v);
43     if(mid+1<=t) change(rs,mid+1,y,s,t,v);
44     update(cur);
45 }
46 void query(int cur,int x,int y,int s,int t,int &ans)
47 {
48     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
49     if(x>=s&&y<=t){
50         ans+=sum[cur];
51         return;
52     }
53     pushdown(cur,x,y);
54     if(mid>=s) query(ls,x,mid,s,t,ans);
55     if(mid+1<=t) query(rs,mid+1,y,s,t,ans);
56 }
57 int main()
58 {
59     int T,n,Q,a,b,c,ans;
60     scanf("%d",&T);
61     for(int i=1;i<=T;i++){
62         ans=0;
63         scanf("%d%d",&n,&Q);
64         build(1,1,n);
65         for(int j=0;j<Q;j++){
66             scanf("%d%d%d",&a,&b,&c);
67             change(1,1,n,a,b,c);
68         }
69         query(1,1,n,1,n,ans);
70         printf("Case %d: The total value of the hook is %d.\n",i,ans);
71     }
72     return 0;
73 }

第二题
POJ3468http://poj.org/problem?id=3468

这是在一段区间上添加值,所以与上题的操作不一样,对于每个相加的数,我们应该也不断将lazy节点累加,类似这种的累加操作,我们总是选择

用add[]数组作为lazy标记

当然这道题特别坑的是因为在累加过程中可以达到10000*100000这样子就超过了int的类型,我们就要用LL来定义sum[],add[]和ans

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 #define N 100005
 6 #define LL long long
 7 int a[N];
 8 LL sum[4*N],add[4*N];
 9 void update(int x)
10 {
11     sum[x]=sum[x<<1]+sum[x<<1|1];
12 }
13 void build(int cur,int x,int y)
14 {
15     add[cur]=0;
16     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
17     if(x==y){
18         sum[cur]=a[x];
19         return;
20     }
21     build(ls,x,mid);
22     build(rs,mid+1,y);
23     update(cur);
24 }
25 void pushdown(int cur,int x,int y)
26 {
27     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
28     if(add[cur]!=0){
29         add[ls]+=add[cur];
30         add[rs]+=add[cur];
31         sum[ls]+=(mid-x+1)*add[cur];
32         sum[rs]+=(y-mid)*add[cur];
33         add[cur]=0;
34     }
35 }
36 void change(int cur,int x,int y,int s,int t,int v)
37 {
38     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
39     if(x>=s&&y<=t){
40         sum[cur]+=(y-x+1)*v;
41         add[cur]+=v;
42         return;
43     }
44     pushdown(cur,x,y);
45     if(mid>=s) change(ls,x,mid,s,t,v);
46     if(mid<t) change(rs,mid+1,y,s,t,v);
47     update(cur);
48 }
49 void query(int cur,int x,int y,int s,int t,LL &ans)
50 {
51     int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1;
52     if(x>=s&&y<=t){
53         ans+=sum[cur];
54         return;
55     }
56     pushdown(cur,x,y);
57     if(mid>=s) query(ls,x,mid,s,t,ans);
58     if(mid<t) query(rs,mid+1,y,s,t,ans);
59 }
60 int main()
61 {
62     int q,n,x,y,z;
63     char c;
64     while(scanf("%d%d",&n,&q)!=EOF){
65         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
66         build(1,1,n);
67         for(int i=1;i<=q;i++){
68             cin>>c;
69             if(c==‘C‘){
70                 scanf("%d%d%d",&x,&y,&z);
71                 change(1,1,n,x,y,z);
72             }
73             else{
74                 scanf("%d%d",&x,&y);
75                 LL ans=0;
76                 query(1,1,n,x,y,ans);
77                 printf("%I64d\n",ans);
78             }
79         }
80     }
81     return 0;
82 }

对于在线段树上修改整段区间的理解,布布扣,bubuko.com

时间: 2024-12-08 01:26:20

对于在线段树上修改整段区间的理解的相关文章

Codeforces 487B. Strip(求区间最值+线段树上的dp)

B. Strip time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Alexandra has a paper strip with n numbers on it. Let's call them ai from left to right. Now Alexandra wants to split it into some p

POJ 2750 Potted Flower (单点修改求线段树上最大子序列和)

题目大意: 在一个序列上每次修改一个值,然后求出它的最大的子序列和. 思路分析: 首先我们不考虑不成环的问题.那就是直接求每个区间的最大值就好了. 但是此处成环,那么看一下下面样例. 5 1 -2 -3 4 5 那么你会发现 max = sum - min 也就是和减去最小区间和也可以得到. 所以我们最后要得到的就是两个东西.注意题目中说的不能全部取得.所以还要判断一下max 是不是等于 sum的. #include <cstdio> #include <iostream> #in

hdu1698 Just a Hook 线段树:成段替换,总区间求和

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecut

NYOJ 1068 ST(线段树之 成段更新+区间求和)

ST 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 "麻雀"lengdan用随机数生成了后台数据,但是笨笨的他被妹纸的问题给难住了... 已知lengdan生成了N(1=<N<=10005)个随机整数,妹子对这些数可能有以下几种操作或询问: 1,A a b c 表示给区间a到b内每个数都加上c: 2,S a b  表示输出区间a到b内的和: 3,Q a b 表示区间a到b内的奇数的个数: 为了使妹纸不口渴,所以我们决定妹纸的询问次数少一点,即

POJ 3468-A Simple Problem with Integers(线段树:成段更新,区间求和)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 62228   Accepted: 19058 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

C - A Simple Problem with Integers POJ - 3468 线段树模版(区间查询区间修改)

参考qsc大佬的视频 太强惹 先膜一下 视频在b站 直接搜线段树即可 1 #include<cstdio> 2 using namespace std; 3 const int maxn=1e5+6; 4 int n,a[maxn]; 5 struct Node{ 6 int l,r; 7 long long sum,lazy; 8 void update(long long x){//用于更新区间和 和懒标记 9 sum+=1ll*(r-l+1)*x; 10 lazy+=x; 11 } 12

CF1083C Max Mex(线段树上二分)

这题卡倍增害我T了一发= = 显然Mex是可以二分的,于是就可以考虑二分一个Mex然后check一下 然后怎么check呢?可以对点权建一棵线段树,节点\([l,r]\)表示,链上点权的集合包括\([l,r]\)时,最短的链的端点 合并两个区间就是在四个端点间选两个作为新链的端点,判断另外两个端点在不在这条链上,在的话这就是一条合法的链.判断方法就是判断一下两段的距离是否等于一整条链的距离. 这样时间复杂度是\(O(nlog^2n)\),感觉可过的样子?然而还可以在线段树上二分把时间复杂度优化到

线段树第二弹(区间更新)

上篇文章,我们介绍了线段树的基本概念和单点更新.区间查询,今天,我们来接着上次的线段树问题继续深入研究.在解决线段树问题的过程中,我们会遇到要求修改区间中某一元素值的问题,当然也可能会遇到要求修改一段子区间所有值的问题--即区间更新问题.回忆一下上篇文章单点更新的方法是,由叶节点逐级向上进行更新,此时更新一个节点值的时间复杂度为o(log n),(点击链接了解详情:线段树+RMQ问题第二弹),那么以这样的处理效率来进行区间更新结果会怎样?现在假设待更新区间数据的规模为 n ,那么就需要进行 n

【BZOJ】4293: [PA2015]Siano 线段树上二分

[题意]给定n棵高度初始为0的草,每天每棵草会长高a[i],m次收割,每次在d[i]天将所有>b[i]的草收割到b[i],求每次收割量.n<=500000. [算法]线段树上二分 [题解]按照生长速度a[]排序后,容易发现数列永远单调. 在线段树上的区间维护以下值: 1.最后一棵草的高度a 2.上次收割日期b 3.总的草高和c 4.总的生长速度和d 5.收割标记D和B 上传的时候注意右区间收割晚于左区间时强制合并. 下传的时候注意标记D和B直接覆盖. 线段树上二分: 1.判断当前区间是否符合(