SPOJ GSS1 静态区间求解最大子段和

题目大意:

给定n个数,再给q个区间询问,希望在区间s,t中找到一段连续的子序列使其和最大

因为询问上万,节点数50000,明显是用线段树去做,这里很明显的区间更新,唯一写起来有点恶心的是询问

每一个区间的最大都要跟左右区间的左最大右最大有关系

反正时要注意细节了,查询的时候同时要查询其左右连续最大

自己的错误在于左右连续最大的更新出问题,这个希望自己以后要注意

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <set>
 6 #include <map>
 7 using namespace std;
 8
 9 const int INF = 0x3fffffff;
10 #define N 50010
11 #define MOD 100007
12 #define ls o<<1
13 #define rs o<<1|1
14 #define define_m int m=(l+r)>>1
15
16 int ml[N*3] , mr[N*3] , mx[N*3] , sum[N*3];
17 int a[N] , pre[N] , n;
18
19 void push_up(int o)
20 {
21     mx[o] = max(mx[ls] , mx[rs]);
22     mx[o] = max(mx[o] , ml[rs]+mr[ls]);
23     ml[o] = max(ml[ls],sum[ls]+ml[rs]) , mr[o] = max(mr[rs],sum[rs]+mr[ls]);
24     sum[o] = sum[ls]+sum[rs];
25 }
26
27 void build(int o , int l , int r)
28 {
29     if(l==r){
30         sum[o]=ml[o]=mr[o]=mx[o]=a[l];
31         return;
32     }
33     define_m;
34     build(ls , l , m);
35     build(rs , m+1 , r);
36     push_up(o);
37 }
38
39 void query(int o , int l , int r , int s , int t , int &ansl , int &ansr , int &ans)
40 {
41     if(l>=s && r<=t){
42         ans = mx[o];
43         ansl = ml[o];
44         ansr = mr[o];
45         return ;
46     }
47     define_m;
48     if(m>=t) query(ls , l , m , s , t , ansl , ansr , ans);
49     else if(m<s) query(rs , m+1 , r , s , t , ansl , ansr ,ans);
50     else{
51         int t1,t2,t3,t4,t5,t6;
52         query(ls , l , m , s , m , t1 , t2 , t3);
53         query(rs , m+1 , r , m+1 , t , t4 , t5 , t6);
54         ansl = max(t1 , pre[m]-pre[s-1]+t4) , ansr = max(t5 , pre[t]-pre[m]+t2);
55         ans = max(t3 , t6);
56         ans = max(ans , t2+t4);
57     }
58     //cout<<o<<" "<<l<<" "<<r<<" "<<s<<" "<<t<<" "<<ansl<<" "<<ansr<<" "<<ans<<endl;
59 }
60
61 int main()
62 {
63     #ifndef ONLINE_JUDGE
64         freopen("a.in" , "r" , stdin);
65     #endif // ONLINE_JUDGE
66     while(~scanf("%d" , &n))
67     {
68         for(int i=1 ; i<=n ; i++){
69             scanf("%d" , a+i);
70             pre[i] = pre[i-1]+a[i];
71         }
72         build(1 , 1 , n);
73         int m;
74         scanf("%d" , &m);
75         for(int i=0 ; i<m ; i++){
76             int s , t;
77             scanf("%d%d" , &s , &t);
78             int t1,t2,t3;
79             query(1,1,n,s,t,t1,t2,t3);
80             printf("%d\n" , t3);
81         }
82     }
83     return 0;
84 }
时间: 2024-11-07 02:16:34

SPOJ GSS1 静态区间求解最大子段和的相关文章

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

HDU3473--Minimum Sum(静态区间第k大)

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3047    Accepted Submission(s): 701 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

静态主席树总结(静态区间的k大)

静态主席树总结(静态区间的k大) 首先我们先来看一道题 给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个正整数,表示这个序列各项的数字. 接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间[l, r][l,r] 内的第k小值. 输出格式: 输出包含k行,每行1个正整数,依次表示每一次查询的结果 对于100%的数据满足:\(1 \leq N, M \leq 2\cdot

主席树(静态区间第k大)

前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建一棵新的线段树,用来记录出现每个数字出现了多少次的前缀和. 那么假设要求区间[l,r]的第k大,将第r棵线段树减去第l-1棵线段树,像上面求所有数的第k大一样来求就可以了. 但是,对于每一个数都建一个线段树显然会爆空间. 现在考虑如何节约空间. 假设现在有四个数1 4 2 3,依次加入,可以这样处理

Can you answer these queries I SPOJ - GSS1 (线段树维护区间连续最大值/最大连续子段和)

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. Inp

Spoj 2916 Can you answer these queries V 线段树 求任意重叠区间的最大子段和

题目链接:点击打开链接 题意: T个测试数据 n个数字 q个询问 每个询问 : [x1, y1] [x2, y2] 问: int ans = -inf; for(int i = x1; i <= y1; i++) for(int j = max(x2, i); j <= y2; j++) ans = max(ans, query(i, j)); 思路: query_L(int l, int r) 求的是在区间[l,r]内 ,左端点为l的最大子段和. 其他和GSS3差不多. 分类讨论一下给定的区

Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和

题目链接:点击打开链接 == 原来写1的时候已经把更新函数写好了.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lso

SPOJ GSS1 Can you answer these queries I

Can you answer these queries I Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: GSS164-bit integer IO format: %lld      Java class name: Main You are given a sequence $A[1], A[2], ..., A[N] $. $( |A[i]| \leq

Spoj-DISUBSTR - Distinct Substrings~New Distinct Substrings SPOJ - SUBST1~(后缀数组求解子串个数)

Spoj-DISUBSTR - Distinct Substrings New Distinct Substrings SPOJ - SUBST1 我是根据kuangbin的后缀数组专题来的 这两题题意一样求解字符串中不同字串的个数: 这个属于后缀数组最基本的应用 给定一个字符串,求不相同的子串的个数. 算法分析: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数. 如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]), suffix(sa