【SPOJ】Can you answer these queries I【线段树】
2014-07-23 21:42
302 查看
题意:给出一个数列,m次询问,每次询问每一个区间的最大连续和。
思路:显然是道线段树的题目,线段树中保存三个信息:区间最大连续和,左端点开始的最大连续和,右端点开始的最大连续和。我们先预处理出前n项的和记为num
,每次Push时根据左区间和右区间来更新整个区间。这题的难点是在与询问的时候,我定义了两种询问,一种是询问某一段区间的最大连续和,一种是询问某一段区间的最大左连续和或者是最大右连续和。对于每次询问,若区间刚好是线段树的节点的区间,直接返回该区间的最大连续和。如果不是,则需要第二中询问来协助。具体实现方法看代码中,文字不好叙述。
思路:显然是道线段树的题目,线段树中保存三个信息:区间最大连续和,左端点开始的最大连续和,右端点开始的最大连续和。我们先预处理出前n项的和记为num
,每次Push时根据左区间和右区间来更新整个区间。这题的难点是在与询问的时候,我定义了两种询问,一种是询问某一段区间的最大连续和,一种是询问某一段区间的最大左连续和或者是最大右连续和。对于每次询问,若区间刚好是线段树的节点的区间,直接返回该区间的最大连续和。如果不是,则需要第二中询问来协助。具体实现方法看代码中,文字不好叙述。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 50006 #define mid (l+r>>1) #define lc (d<<1) #define rc (d<<1|1) int num ; struct Tr { int v, lv, rv; }tr[N<<2]; void Push(int d, int l, int r) { tr[d].v = max(tr[lc].v, tr[rc].v); tr[d].lv = tr[lc].lv, tr[d].rv = tr[rc].rv; tr[d].v = max(tr[d].v, tr[lc].rv+tr[rc].lv); tr[d].lv = max(tr[d].lv, tr[rc].lv+num[mid]-num[l-1]); tr[d].rv = max(tr[d].rv, tr[lc].rv+num[r]-num[mid]); } void build(int d, int l, int r) { if (l == r) { tr[d].lv = tr[d].rv = tr[d].v = num[l]-num[l-1]; return; } build(lc, l, mid); build(rc, mid+1, r); Push(d, l, r); } int query_lr(int d, int l, int r, int L, int R, int k) { if (l == L && r == R) { if (k) return tr[d].lv; else return tr[d].rv; } if (R <= mid) return query_lr(lc, l, mid, L, R, k); else if (L > mid) return query_lr(rc, mid+1, r, L, R, k); else { int lm = num[mid]-num[L-1], rm = num[R]-num[mid]; if (k) return max(query_lr(lc, l, mid, L, mid, k), max(lm, lm+query_lr(rc, mid+1, r, mid+1, R, k))); else return max(query_lr(rc, mid+1, r, mid+1, R, k), max(rm, rm+query_lr(lc, l, mid, L, mid, k))); } } int query(int d, int l, int r, int L, int R) { if (L == l && R == r) { return tr[d].v; } if (R <= mid) return query(lc, l, mid, L, R); else if (L > mid) return query(rc, mid+1, r, L, R); else { int tl = query(lc, l, mid, L, mid); int tr = query(rc, mid+1, r, mid+1, R); return max(max(tl, tr), query_lr(lc, l, mid, L, mid,0)+query_lr(rc, mid+1, r, mid+1, R, 1)); } } int main() { int n, i, j, m; while (~scanf("%d", &n)) { num[0] = 0; for (i = 1;i <= n;i++) { scanf("%d", &num[i]); num[i] += num[i-1]; } build(1, 1, n); scanf("%d", &m); while (m--) { scanf("%d%d", &i, &j); printf("%d\n", query(1, 1, n, i, j)); } } }
相关文章推荐
- spoj 1716. Can you answer these queries III(线段树)
- SPOJ GSS5 Can you answer these queries V ——线段树
- [SPOJ GSS5] Can you answer these queries V [线段树]
- spoj 2713. Can you answer these queries IV(线段树)
- SPOJ GSS7 Can you answer these queries VII ——树链剖分 线段树
- SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
- spoj Can you answer these queries I(线段树 单点更新 区间查询)
- 【SPOJ】1557 Can you answer these queries II 线段树
- 【线段树】 SPOJ 1043 Can you answer these queries I 区间合并
- spoj 1716 Can you answer these queries III(线段树)
- Spoj 2916 Can you answer these queries V 线段树 求任意重叠区间的最大子段和
- SPOJ 2916 Can you answer these queries V(线段树-分类讨论)
- 【线段树】 SPOJ 1043 Can you answer these queries I 区间合并
- SPOJ 2713. Can you answer these queries IV(GSS4 线段树)
- 【线段树】 SPOJ 1716 Can you answer these queries III
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
- SPOJ 1043 Can you answer these queries I (超强线段树)
- 【线段树】 SPOJ 1716 Can you answer these queries III
- SPOJ 1557 Can you answer these queries II(离线处理+线段树求历史最大)
- SPOJ 2916 Can you answer these queries V(GSS5 线段树)