线段树-区间增减

输入n和n个数,再输入操作的次数,每次操作的指令为:“1”表示查询,后面输入查询的区间(左右两端点) “2”表示区间增减,后面输入操作的区间(左右两端点)和增加的值(可能为负数)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=1024;
 6 int _sum,_max,_min;
 7 int addv[maxn*2],sumv[maxn*2],minv[maxn*2],maxv[maxn*2];
 8 int y1,y2,v,ql,qr,n;
 9 void cself(int o,int l,int r)
10 {
11     minv[o]=maxv[o]=sumv[o]=0;
12     if(l<r){
13         minv[o]=min(minv[o*2],minv[o*2+1]);
14         sumv[o]=sumv[o*2]+sumv[o*2+1];
15         maxv[o]=max(maxv[o*2],maxv[o*2+1]);
16     }
17     minv[o]+=addv[o],maxv[o]+=addv[o],sumv[o]+=(r-l+1)*addv[o];
18 }
19 void query(int o,int l,int r,int added)
20 {
21     if(ql<=l&&r<=qr){
22         _sum+=(r-l+1)*added+sumv[o];
23         _min=min(_min,minv[o]+added);
24         _max=max(_max,maxv[o]+added);
25     }else{
26         int m=(l+r)/2;
27         if(ql<=m) query(o*2,l,m,added+addv[o]);
28         if(m<qr) query(o*2+1,m+1,r,added+addv[o]);
29     }
30 }
31 void update(int o,int l,int r)
32 {
33     if(y1<=l&&r<=y2){
34         addv[o]+=v;
35     }else{
36         int m=(l+r)/2;
37         if(y1<=m) update(o*2,l,m);
38         if(m<y2) update(o*2+1,m+1,r);
39     }
40     cself(o,l,r);
41 }
42 void buildTree()
43 {
44     for(int i=1;i<=n;i++)
45     {
46         scanf("%d",&v);
47         y2=y1=i;
48         update(1,1,n);
49     }
50 }
51 void ansQuestion(int q)
52 {
53     int op;
54     for(int i=1;i<=q;i++)
55     {
56         scanf("%d",&op);
57         if(op==1)//查询
58         {
59             _sum=0;
60             _min=1<<30;
61             _max=-_min;
62             scanf("%d %d",&ql,&qr);
63             int mmin=min(ql,qr);
64             qr=max(ql,qr);
65             ql=mmin;
66             query(1,1,n,0);
67             printf("sum:%d\tmin:%d\tmax:%d\n",_sum,_min,_max);
68         }else if(op==2)//区间增减
69         {
70             scanf("%d %d %d",&y1,&y2,&v);
71             int mmin=min(y1,y2);
72             y2=max(y1,y2);
73             y1=mmin;
74             update(1,1,n);
75         }else printf("Wrong Operator\n");
76     }
77 }
78 void init()
79 {
80     memset(addv,0,sizeof(addv));
81 }
82 int main()
83 {
84     int q;
85     init();
86     scanf("%d",&n);
87     buildTree();
88     scanf("%d",&q);
89     ansQuestion(q);
90     return 0;
91 }
时间: 2024-07-29 19:16:37

线段树-区间增减的相关文章

POJ 3468 (线段树 区间增减) A Simple Problem with Integers

这题WA了好久,一直以为是lld和I64d的问题,后来发现是自己的pushdown函数写错了,说到底还是因为自己对线段树理解得不好. 因为是懒惰标记,所以只有在区间分开的时候才会将标记往下传递.更新和查询都要pushdown. 1 #include <cstdio> 2 3 typedef long long LL; 4 5 const int maxn = 100000 + 10; 6 7 int n, m, qL, qR, v; 8 LL sum[maxn << 2], add

【POJ】A Simple Problem with Integers(线段树区间修增减求和)

线段树区间修改增加问题,模板题,注意懒惰处理. 13443449 201301052100 3468 Accepted 4308K 1610MS C++ 2362B 2014-09-15 15:46:35 #include<cstdio> #include<cstring> #include<iostream> #include<vector> #include<queue> #include<map> #include<cst

POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】

Hotel Time Limit: 3000MS Memory Limit: 65536K 链接:POJ 3667   Description The cows are journeying north to ThunderBay in Canada to gain cultural enrichment and enjoy a vacation on the sunnyshores of Lake Superior. Bessie, ever the competent travel agen

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i

HDU 1689 Just a Hook 线段树区间更新求和

点击打开链接 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18894    Accepted Submission(s): 9483 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是

POJ 3667 线段树区间合并

http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html 用线段树,首先要定义好线段树的节点信息,一般看到一个问题,很难很快能确定线段树要记录的信息做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析回忆一下RMQ问题,其实解决RMQ有很多方法,根本不需要用到线段树,用线段树解决RMQ,其实是利用线段树的性质来辅助解决这个问题回忆一下求矩形面积并或周长并的问题,一般使用的是扫描

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1