SPOJ GSS系列(数据结构维护技巧入门)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ GSS系列(数据结构维护技巧入门)相关的知识,希望对你有一定的参考价值。
题目链接 GSS
GSS1
对于每个询问li, ri,查询a[li], a[li + 1], a[li + 2], ..., a[ri]这个序列的最大字段和。
建立线段树,每个节点维护四个信息
c:当前区间的元素和
lc:当前区间左端点开始的最大子序列和
rc:当前区间右端点结束的最大子序列和
ret:当前区间的答案
于是我们建立线段树的时候预处理出每个节点的四个信息,查询的时候返回一个节点,这个节点的ret记即为答案。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R #define ls i << 1 #define rs i << 1 | 1 typedef long long LL; const int N = 1e5 + 10; struct node{ int c, lc, rc, ret; } t[N << 2]; int n, q, l, r; void pushup(int i){ t[i].c = t[ls].c + t[rs].c; t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc); t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc); t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc); } void build(int i, int L, int R){ if (L == R){ scanf("%d", &t[i].ret); t[i].c = t[i].lc = t[i].rc = t[i].ret; return; } int mid = (L + R) >> 1; build(lson); build(rson); pushup(i); } node query(int i, int L, int R, int l, int r){ if (l == L && R == r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r); if (l > mid) return query(rson, l, r); node ta = query(lson, l, mid); node tb = query(rson, mid + 1, r); node ans; ans.c = ta.c + tb.c; ans.lc = max(ta.lc, ta.c + tb.lc); ans.rc = max(tb.rc, tb.c + ta.rc); ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc); return ans; } int main(){ while (~scanf("%d", &n)){ build(1, 1, n); scanf("%d", &q); while (q--){ scanf("%d%d", &l, &r); node ans = query(1, 1, n, l, r); printf("%d\n", ans.ret); } } return 0; }
GSS2
GSS1的去重版
什么意思呢
询问的形式还是完全一样的,就是子序列的价值稍微变了一下。
GSS1中子序列的价值是该子序列的元素和,GSS2这里是该子序列出现过的元素的和
做法和GSS1完全不一样。
我们对询问离线。然后排序,按照右端点升序。
然后从左往右扫过去,每次加入a[i]的时候, 先把a[i]加进去。
接着我们对last[a[i]] + 1到i - 1这段区间都加上a[i],last[x]表示x上一次出现的位置,初值为0。
维护线段树的话我们需要四个信息。
now:当前这个时候区间的最大值
mx:历史区间的最大值
h:历史lazy标记(传给后代)的最大值
add:当前lazy标记(需传给后代)的值
然后查询一遍就可以了。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R #define ls i << 1 #define rs i << 1 | 1 #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 1e5 + 10; const int d = 1e5; int n, m, x, y; int a[N], c[N << 1]; vector <pair <int, int> > v[N]; LL mx[N << 2], now[N << 2], add[N << 2], h[N << 2]; LL ans[N]; void pushup(int i){ mx[i] = max(mx[ls], mx[rs]); now[i] = max(now[ls], now[rs]); } void pushdown(int i){ h[ls] = max(h[ls], add[ls] + h[i]); h[rs] = max(h[rs], add[rs] + h[i]); add[ls] += add[i]; add[rs] += add[i]; mx[ls] = max(mx[ls], now[ls] + h[i]); mx[rs] = max(mx[rs], now[rs] + h[i]); now[ls] += add[i]; now[rs] += add[i]; add[i] = 0; h[i] = -1e16; } void update(int i, int L, int R, int x, int val){ if (L == R && L == x){ mx[i] = now[i] = val; return; } int mid = (L + R) >> 1; pushdown(i); if (x <= mid) update(lson, x, val); else update(rson, x, val); pushup(i); } void Add(int i, int L, int R, int l, int r, int val){ if (l <= L && R <= r){ now[i] += val; mx[i] = max(mx[i], now[i]); add[i] += val; h[i] = max(h[i], add[i]); return ; } int mid = (L + R) >> 1; pushdown(i); if (l <= mid) Add(lson, l, r, val); if (r > mid) Add(rson, l, r, val); pushup(i); } LL query(int i, int L, int R, int l, int r){ if (l <= L && R <= r) return mx[i]; int mid = (L + R) >> 1; LL ret = -1e16; pushdown(i); if (l <= mid) ret = max(ret, query(lson, l, r)); if (r > mid) ret = max(ret, query(rson, l, r)); pushup(i); return ret; } int main(){ scanf("%d", &n); rep(i, 1, n) scanf("%d", a + i); scanf("%d", &m); rep(i, 1, ((n << 2) - 1)) mx[i] = h[i] = now[i] = -1e16; rep(i, 1, m){ scanf("%d%d", &x, &y); v[y].push_back(MP(x, i)); } rep(i, 1, n){ update(1, 1, n, i, a[i]); if (c[a[i] + d] + 1 < i) Add(1, 1, n, c[a[i] + d] + 1, i - 1, a[i]); c[a[i] + d] = i; for (auto u : v[i]) ans[u.se] = query(1, 1, n, u.fi, i); } rep(i, 1, m) printf("%lld\n", max(0ll, ans[i])); return 0; }
以上是关于SPOJ GSS系列(数据结构维护技巧入门)的主要内容,如果未能解决你的问题,请参考以下文章
Can you answer these queries I SPOJ - GSS1 (线段树维护区间连续最大值/最大连续子段和)