题目链接:https://vjudge.net/problem/SPOJ-GSS1

 

GSS1 - Can you answer these queries I

 

You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defined as follows: 
Query(x,y) = Max { a[i]+a[i+1]+...+a[j] ; x ≤ i ≤ j ≤ y }. 
Given M queries, your program must output the results of these queries.

Input

  • The first line of the input file contains the integer N.
  • In the second line, N numbers follow.
  • The third line contains the integer M.
  • M lines follow, where line i contains 2 numbers xi and yi.

Output

Your program should output the results of the M queries, one query per line.

Example

Input:
3 
-1 2 3
1
1 2

Output:
2

 

 

题意:

给出一个序列。有m个询问:区间[L,R]里的最大连续和是多少?

 

题解:

1.线段树的结点信息合并。将这n个数按线段树的形式分割下去,然后再从最底层的小区间,往上合并得到大区间:两个对应的小区间有四种合并结果(得到一段连续的区间):1.左连续、右连续、左右不连续、全连续。记录每种合并结果的最大值。

2.对于询问区间,依旧如普通的查询操作一样,拿到线段树里与对应区间,但是需要注意的是:当询问区间被mid分成两段时,需要单独单出来,然后再尝试将两段进行信息合并。

 

代码如下:

SPOJ - GSS1 —— 线段树 (结点信息合并)_#includeSPOJ - GSS1 —— 线段树 (结点信息合并)_区间合并_02
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const double EPS = 1e-8;
15 const int INF = 2e9;
16 const LL LNF = 2e18;
17 const int MAXN = 5e4+10;
18 
19 struct node
20 {
21     int a[4];
22 };
23 node sum[MAXN<<2];
24 
25 /*
26     0:两边不连续
27     1:左连续
28     2:右连续
29     3:全连续
30 */
31 void push_up(int fa[], int s1[], int s2[])
32 {
33     fa[0] = max(max(s1[0], s2[0]),max(max(s1[2],s2[1]), s1[2]+s2[1]));
34     fa[1] = max(max(s1[1],s1[3]), s1[3]+s2[1]);
35     fa[2] = max(max(s2[2],s2[3]), s1[2]+s2[3]);
36     fa[3] = s1[3] + s2[3];
37 }
38 
39 void build(int u, int l, int r)
40 {
41     if(l==r)
42     {
43         scanf("%d", &sum[u].a[3]);  //只有一个点,当然是全连续
44         sum[u].a[0] = sum[u].a[1] = sum[u].a[2] = -15007;   //其他情况设为不可能
45         return;
46     }
47 
48     int mid = (l+r)>>1;
49     build(u*2, l, mid);
50     build(u*2+1, mid+1, r);
51     push_up(sum[u].a, sum[u*2].a, sum[u*2+1].a);
52 }
53 
54 node query(int u, int l, int r, int x, int y)
55 {
56     if(x<=l && r<=y)
57         return sum[u];
58 
59     int mid = (l+r)>>1;
60     node ret;
61     if(y<=mid)  //询问区间在左边
62         ret = query(u*2, l, mid, x, y);
63     else if(x>=mid+1)   //询问区间在右边
64         ret = query(u*2+1, mid+1, r, x, y);
65     else    //询问区间被分割成两段,因而还要调用push_up尝试将两子区间合并
66     {
67         node t1 = query(u*2, l, mid, x, mid);
68         node t2 = query(u*2+1, mid+1, r, mid+1, y);
69         push_up(ret.a, t1.a, t2.a);
70     }
71     return ret;
72 }
73 
74 int main()
75 {
76     int n, m;
77     scanf("%d", &n);
78     build(1,1,n);
79     scanf("%d", &m);
80     while(m--)
81     {
82         int l, r;
83         scanf("%d%d", &l,&r);
84         node ret = query(1,1,n,l,r);
85         int t1 = max(ret.a[0], ret.a[1]);   //取四种连续情况的最大值
86         int t2 = max(ret.a[2], ret.a[3]);
87         printf("%d\n", max(t1,t2));
88     }
89 }
View Code