codevs 3981 动态最大子段和(线段树)

题目传送门:codevs 3981 动态最大子段和

题目描述 Description

题目还是简单一点好...

有n个数,a[1]到a[n]。

接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和。

子段的意思是连续非空区间。

输入描述 Input Description

第一行一个数n。

第二行n个数a[1]~a[n]。

第三行一个数q。

以下q行每行两个数l和r。

输出描述 Output Description

q行,每行一个数,表示a[l]到a[r]的最大子段和。

样例输入 Sample Input

7
2 3 -233 233 -23 -2 233
4
1 7
5 6
2 5
2 3

样例输出 Sample Output

441
-2
233
3

数据范围及提示 Data Size & Hint

对于50%的数据,q*n<=10000000。

对于100%的数据,1<=n<=200000,1<=q<=200000。

a[1]~a[n]在int范围内,但是答案可能超出int范围。

数据保证1<=l<=r<=n。

空间128M,时间1s。

题目大意:

  求解区间 a[l]~a[r] 的最大子段和

解题思路:

  用线段树维护区间最大值。开几个变量存区间和sum,完全在左区间的最大值max_l,完全在右区间的最大值max_r,跨左右区间的最大值max。

 1 #include <bits/stdc++.h>
 2 #define lson rt<<1,l,mid
 3 #define rson rt<<1|1,mid+1,r
 4 using namespace std;
 5 const int N = 200000 + 10;
 6 typedef long long int ll;
 7 struct node
 8 {
 9     int l,r;
10     ll max_,max_l,max_r,sum;
11 } a[N<<2];
12 int n,q,x,y;
13 ll ans;
14 void up(int rt)
15 {
16     a[rt].max_=max(max(a[rt<<1].max_,a[rt<<1|1].max_),a[rt<<1].max_r+a[rt<<1|1].max_l);
17     a[rt].max_l=max(a[rt<<1].max_l,a[rt<<1].sum+a[rt<<1|1].max_l);
18     a[rt].max_r=max(a[rt<<1|1].max_r,a[rt<<1|1].sum+a[rt<<1].max_r);
19     a[rt].sum=a[rt<<1].sum+a[rt<<1|1].sum;
20 }
21 void build(int rt,int l,int r)
22 {
23     a[rt].l=l,a[rt].r=r;
24     if (l==r)
25     {
26         scanf("%lld",&a[rt].max_);
27         a[rt].max_l=a[rt].max_r=a[rt].sum=a[rt].max_;
28         return ;
29     }
30     int mid = (l+r)>>1;
31     build(lson);
32     build(rson);
33     up(rt);
34 }
35 void query(int rt,int L,int R,ll &ans,ll &ansl,ll &ansr)
36 {
37     if (L<=a[rt].l&&a[rt].r<=R)
38     {
39         ans=a[rt].max_;
40         ansl=a[rt].max_l;
41         ansr=a[rt].max_r;
42         return ;
43     }
44     int mid=(a[rt].l+a[rt].r)>>1;
45     if (mid>=R) query(rt<<1,L,R,ans,ansl,ansr);
46     else if (mid<L) query(rt<<1|1,L,R,ans,ansl,ansr);
47     else
48     {
49         ll lans=0,lansl=0,lansr=0,rans=0,ransl=0,ransr=0;
50         query(rt<<1,L,R,lans,lansl,lansr);
51         query(rt<<1|1,L,R,rans,ransl,ransr);
52         ans=max(max(lans,rans),lansr+ransl);
53         ansl=max(lansl,ransl+a[rt<<1].sum);
54         ansr=max(ransr,lansr+a[rt<<1|1].sum);
55     }
56 }
57 int main()
58 {
59     scanf("%d",&n);
60     build(1,1,n);
61     for ( scanf("%d",&q); q; q--)
62     {
63         scanf("%d%d",&x,&y);
64         ll ans=0,ansl=0,ansr=0;
65         query(1,x,y,ans,ansl,ansr);
66         printf("%lld\n",ans);
67     }
68     return 0;
69 }

原文地址:https://www.cnblogs.com/l999q/p/9454303.html

时间: 2024-08-29 22:34:54

codevs 3981 动态最大子段和(线段树)的相关文章

codevs 3981 动态最大子段和

3981 动态最大子段和 http://codevs.cn/problem/3981/  题目等级 : 钻石 Diamond 题目描述 Description 题目还是简单一点好... 有n个数,a[1]到a[n]. 接下来q次查询,每次动态指定两个数l,r,求a[l]到a[r]的最大子段和. 子段的意思是连续非空区间. 输入描述 Input Description 第一行一个数n. 第二行n个数a[1]~a[n]. 第三行一个数q. 以下q行每行两个数l和r. 输出描述 Output Desc

SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树

题目链接:点击打开链接 维护区间左起连续的最大和,右起连续的和.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lson

xdoj1023 IP查询 动态开点的线段树

xdoj1023 IP查询    动态开点的线段树 1023: IP查询 时间限制: 1 Sec  内存限制: 128 MB提交: 3473  解决: 228[提交][状态][讨论版] 题目描述 现实生活中,每一个IP段都指向一座城市.为了简化问题,我们将IP段直接看做一个整形数,每座城市也有自己的唯一标识ID,也可以看做一个整数.那么问题来了,现在已知有多个闭区间代表多个IP段,每个区间对应一个城市的ID.现在,小L要查询某个IP属于那个城市,希望聪明的你来帮他完成. 输入 第一行输入T,表示

xdoj1065 Efficent Allocation 动态开点的线段树

xdoj1065 Efficent Allocation  动态开点的线段树 1065: Efficent Allocation 时间限制: 8 Sec  内存限制: 256 MB提交: 24  解决: 3[提交][状态][讨论版] 题目描述 由于XDOJ评测机的一些奇怪行为,本题时限调整到8s. lx正在写一个内存分配器,支持下列操作: (1) malloc(size),分配一个大小为size字节的内存块,返回指向该内存块的指针. (2) free(p),释放起始地址是p的内存块. lx使用的

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

SPOJ GSS系列 最大子段和 线段树+树链剖分+splay 1043 1557 1716 2713 2916 4487 6779

最大子段和的各种形式 题解内附每道题的 题意 题目链接 思路 SPOJ 1043 GSS1 静态区间求个最大子段和, 题解 SPOJ 1577 GSS2 和1一样,区别是若区间内存在相同的元素,则该元素只计算一次. 离线一下然后使劲跑.. 题解 SPOJ 1716 GSS3 和1一样,就是要支持单点修改 题解 SPOJ 2713 GSS4 ==普通线段树,感觉和这系列关系不大. 题解 SPOJ 2916 GSS5 题意有点怪,,跟3差不多,就是稍加强了点询问 题解 SPOJ 4487 GSS6

扫描线讲解,动态开点版线段树

扫描线 首先,扫描线是干什么的?扫描线一般运用在图形上面,它和它的字面意思十分相似,就是一条线在整个图上扫来扫去,它一般被用来解决图形面积,周长等问题,以一道例题为例.给出n个正方形,这些正方形在平面直角坐标系中互相重叠摆放,但四条边都与坐标轴平行,例如下图所示.那么知道题目了,怎么运用呢?首先我们需要知道怎么用暴力解决这个问题,根据图片可知图中的面积是SABCD+SHEFG-SIDJE暴力搜索是个好东西,但是当数据范围大了怎么办?这里就要讲到扫描线. 扫描线对于这道例题可以抽象为这四条紫色的直

p1115 最大子段和(线段树)

题目描述-->p1115 最大子段和 虽然是一个普及-的题,但我敲了线段树 qwq 数组定义 \(lsum[ ]\)代表 该区间左端点开始的最大连续和. \(rsum[ ]\)代表 该区间右端点开始的最大连续和. \(ssum[ ]\)代表 区间内最大连续和. \(sum[ ]\) 代表区间和. Que and A Q:已知一个区间的左右区间的最大连续和,如何合并? A:这个区间的最大连续和要么是左子区间的最大连续和,要么是右子区间的最大连续和. 要么是左子区间的最大右起子段和+右子区间的最大左

算法学习——动态图连通性(线段树分治+按秩合并并查集)

在考场上遇到了这个的板子题,,,所以来学习了一下线段树分治 + 带撤销的并查集. 题目大意是这样的:有m个时刻,每个时刻有一个加边or撤销一条边的操作,保证操作合法,没有重边自环,每次操作后输出当前图下所有联通块大小的乘积. 首先观察到如果没有撤销操作,那么直接用并查集就可以维护,每次合并的时候乘上要合并的两个并查集大小的逆元,然后乘上合并之后的大小即可. 那么来考虑撤销,观察到如果并查集不带路径压缩,应该是可以处理撤销操作的. 但我们并不能直接做,因为并查集的撤销必须按顺序来,就相当于每次合并