【SPOJ】GSS总结
首先Orz zhonghaoxi找的的神题
GSS1
Can you answer these queries I : http://www.spoj.com/problems/GSS1/
求区间最大子序和
考虑记录三个标记:tot(区间最大子序和),left(从区间左端开始向右的最大子序和),right(从区间右端开始向左的最大子序和)
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 #define maxn 50100 4 #define INF 1 << 30 5 #define For(i, n) for (int i = 1; i <= n; i++) 6 #define lson l, mid, rt << 1 7 #define rson mid + 1, r, rt << 1 | 1 8 #define L rt << 1 9 #define R rt << 1 | 1 10 using namespace std; 11 int n, a[maxn], ans; 12 struct SegmentTree { 13 int tot[maxn << 2], sum[maxn << 2], left[maxn << 2], right[maxn << 2]; 14 void Update(int rt) { 15 sum[rt] = sum[L] + sum[R]; 16 tot[rt] = max(tot[L], tot[R]); tot[rt] = max(tot[rt], left[R] + right[L]); 17 left[rt] = max(left[L], sum[L] + left[R]); 18 right[rt] = max(right[R], sum[R] + right[L]); 19 } 20 void build(int l, int r, int rt) { 21 if (l == r) { 22 sum[rt] = tot[rt] = left[rt] = right[rt] = a[l]; 23 return; 24 } 25 int mid = (l + r) >> 1; build(lson), build(rson), Update(rt); 26 } 27 int query(int flag, int x, int y, int l, int r, int rt) { 28 int mid = (l + r) >> 1; 29 if (x <= l && r <= y) { 30 ans = max(ans, tot[rt]); 31 if (flag) return right[rt]; else return left[rt]; 32 } 33 if (y <= mid) return query(0, x, y, lson); else if (mid + 1 <= x) return query(1, x, y, rson); 34 int ln = query(1, x, y, lson), rn = query(0, x, y, rson); ans = max(ans, ln + rn); 35 if (flag) return max(right[R], sum[R] + ln); else return max(left[L], sum[L] + rn); 36 } 37 }seg; 38 int main() { 39 scanf("%d\n", &n); 40 For(i, n) scanf("%d", &a[i]); seg.build(1, n, 1); 41 int m, x, y; scanf("%d", &m); 42 while (m--) { 43 scanf("%d%d", &x, &y); ans = -INF; 44 seg.query(0, x, y, 1, n, 1); 45 printf("%d\n", ans); 46 } 47 return 0; 48 }
GSS2
Can you answer these queries II : http://www.spoj.com/problems/GSS2/
求区间最大子序列和,区间相同元素的值只加一次
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifdef unix 2 #define LLD "%lld" 3 #else 4 #define LLD "%I64d" 5 #endif 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #define LL long long 10 #define maxn 200010 11 #define S 100000 12 #define For(i, n) for (int i = 1; i <= n; i++) 13 #define lson l, mid , rt << 1 14 #define rson mid + 1, r, rt << 1 | 1 15 #define L rt << 1 16 #define R rt << 1 | 1 17 using namespace std; 18 struct SegmentTree { 19 int nowsum[maxn << 2], nowup[maxn << 2], totsum[maxn << 2], totup[maxn << 2]; 20 void build(int l, int r, int rt) { 21 nowsum[rt] = nowup[rt] = totsum[rt] = totup[rt] = 0; 22 if (l != r) { 23 int mid = (l + r) >> 1; 24 build(lson), build(rson); 25 } 26 } 27 void PushUp(int rt) { 28 totsum[rt] = max(totsum[L], totsum[R]) + nowsum[rt]; 29 totup[rt] = max(totup[L], totup[R]); 30 totup[rt] = max(totup[rt], max(totsum[L], totsum[R]) + nowup[rt]); 31 } 32 void Down(int a, int b) { 33 nowup[b] = max(nowup[b], nowsum[b] + nowup[a]), nowsum[b] += nowsum[a]; 34 PushUp(b); 35 } 36 void PushDown(int rt) {Down(rt, L), Down(rt, R);nowsum[rt] = nowup[rt] = 0;} 37 void Update(int x, int y, int val, int l, int r, int rt) { 38 if (x <= l && r <= y) { 39 nowsum[rt] += val; 40 nowup[rt] = max(nowup[rt], nowsum[rt]); 41 PushUp(rt); 42 } else { 43 int mid = (l + r) >> 1; 44 PushDown(rt); 45 if (x <= mid) Update(x, y, val, lson); 46 if (y > mid) Update(x, y, val, rson); 47 PushUp(rt); 48 } 49 } 50 LL Query(int x, int y, int l, int r, int rt) { 51 if (x <= l && r <= y) return totup[rt]; 52 else { 53 int mid = (l + r) >> 1;LL ret = 0; 54 PushDown(rt); 55 if (x <= mid) ret = max(ret, Query(x, y, lson)); 56 if (y > mid) ret = max(ret, Query(x, y, rson)); 57 return ret; 58 } 59 } 60 }seg; 61 struct node{int l, r, pos;}Q[maxn]; 62 int cmp(node a, node b) {return a.r < b.r;} 63 int pos[maxn], a[maxn]; 64 LL ans[maxn]; 65 int main() { 66 int n, q; 67 while (~scanf("%d", &n)) { 68 seg.build(1, n, 1); 69 memset(pos, 0, sizeof(pos)); 70 For(i, n) scanf("%d", &a[i]); 71 scanf("%d", &q); For(i, q) scanf("%d%d", &Q[i].l, &Q[i].r), Q[i].pos = i; 72 sort(Q + 1, Q + 1 + q, cmp); 73 for(int i = 1, j = 1; i <= n && j <= q; i++) { 74 seg.Update(pos[a[i] + S] + 1, i, a[i], 1, n, 1); 75 pos[a[i] + S] = i; 76 while (j <= q && i == Q[j].r) ans[Q[j].pos] = seg.Query(Q[j].l, Q[j].r, 1, n, 1), j++; 77 } 78 For(i, q) printf(LLD "\n", ans[i]); 79 } 80 return 0; 81 }
GSS3
Can you answer these queries III : http://www.spoj.com/problems/GSS3/
区间最大子序和(同GSS1)+单点修改(基本操作吧)
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifdef unix 2 #define LLD "%lld" 3 #else 4 #define LLD "%I64d" 5 #endif 6 #include <cstdio> 7 #include <algorithm> 8 #define LL long long 9 #define maxn 50010 10 #define INF 1 << 30 11 #define lson l, mid, rt << 1 12 #define rson mid + 1, r, rt << 1 | 1 13 #define L rt << 1 14 #define R rt << 1 | 1 15 #define For(i, n) for (int i = 1; i <= n; i++) 16 using namespace std; 17 int n, m, a[maxn];LL ans; 18 struct SegmentTree { 19 LL left[maxn << 2], right[maxn << 2], tot[maxn << 2], sum[maxn << 2]; 20 void Update(int rt) { 21 sum[rt] = sum[L] + sum[R]; 22 tot[rt] = max(tot[L], tot[R]); tot[rt] = max(tot[rt], left[R] + right[L]); 23 left[rt] = max(left[L], sum[L] + left[R]); 24 right[rt] = max(right[R], sum[R] + right[L]); 25 } 26 void build(int l, int r, int rt) { 27 if (l == r) { 28 sum[rt] = left[rt] = right[rt] = tot[rt] = a[l]; 29 return; 30 } 31 int mid = (l + r) >> 1; 32 build(lson), build(rson), Update(rt); 33 } 34 void Change(int key, int val, int l, int r, int rt) { 35 if (l == r) { 36 sum[rt] = tot[rt] = left[rt] = right[rt] = val; 37 return; 38 } 39 int mid = (l + r) >> 1; 40 if (key <= mid) Change(key, val, lson); else Change(key, val, rson); 41 Update(rt); 42 } 43 LL Query(int flag, int x, int y, int l, int r, int rt) { 44 int mid = (l + r) >> 1; 45 if (x <= l && r <= y) { 46 ans = max(ans, tot[rt]); 47 if (flag) return right[rt]; else return left[rt]; 48 } 49 if (y <= mid) return Query(0, x, y, lson); else if (mid + 1 <= x) return Query(1, x, y, rson); 50 LL ln = Query(1, x, y, lson), rn = Query(0, x, y, rson); ans = max(ans, ln + rn); 51 if (flag) return max(right[R], sum[R] + ln); else return max(left[L], sum[L] + rn); 52 } 53 }seg; 54 int main() { 55 while (scanf("%d", &n) == 1) { 56 For(i, n) scanf("%d", &a[i]); seg.build(1, n, 1); 57 scanf("%d", &m); 58 while (m--) { 59 int x, y, z; scanf("%d%d%d", &z, &x, &y); 60 if (z == 0) seg.Change(x, y, 1, n, 1); 61 else { 62 ans = -INF; seg.Query(0, x, y, 1, n, 1); 63 printf(LLD "\n", ans); 64 } 65 } 66 } 67 return 0; 68 }
GSS4
Can you answer these queries IV : http://www.spoj.com/problems/GSS4/
区间求和+将给定区间内所有元素更新为其算数平方根
(考虑一个数开根次数有限,当多次开根后,最后被开成0或1就不用再更新了。只用记录每一个数是否能继续开根,每次更新时就沿着没有开尽的地方更新到底)
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifdef unix 2 #define LLD "%lld" 3 #else 4 #define LLD "%I64d" 5 #endif 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <string> 10 #include <iostream> 11 #include <cmath> 12 #define LL long long 13 #define maxn 100010 14 #define INF 1 << 30 15 #define For(i, n) for (int i = 1; i <= n; i++) 16 #define rep(i, j, k) for (int i = j; i <= k; i++) 17 #define L rt << 1 18 #define R rt << 1 | 1 19 #define lson l, mid, rt << 1 20 #define rson mid + 1, r, rt << 1 | 1 21 using namespace std; 22 void file(string s) { 23 string in = s + ".in", ou = s + ".out"; 24 freopen(in.c_str(), "r", stdin); 25 freopen(ou.c_str(), "w", stdout); 26 } 27 LL a[maxn];int n; 28 struct SegmentTree { 29 LL sum[maxn << 2];int done[maxn << 2]; 30 void Update(int rt) { 31 sum[rt] = sum[L] + sum[R]; 32 if (done[L] && done[R]) done[rt] = 1; else done[rt] = 0; 33 } 34 void build(int l, int r, int rt) { 35 int mid = (l + r) >> 1; 36 if (l == r) { 37 sum[rt] = a[l]; 38 if (a[l] == 0 || a[l] == 1) done[rt] = 1; else done[rt] = 0; 39 return; 40 } 41 build(lson), build(rson), Update(rt); 42 } 43 void dfs(int l, int r, int rt) { 44 int mid = (l + r) >> 1; 45 if (l == r) { 46 sum[rt] = (LL) sqrt(sum[rt] + 0.5); 47 if (sum[rt] == 0 || sum[rt] == 1) done[rt] = 1; 48 return; 49 } 50 if (!done[L]) dfs(lson); if (!done[R]) dfs(rson); 51 Update(rt); 52 } 53 LL Query(int x, int y, int l, int r, int rt) { 54 int mid = (l + r) >> 1; 55 if (x <= l && r <= y) return sum[rt]; 56 if (mid >= y) return Query(x, y, lson); 57 else if (mid + 1 <= x) return Query(x, y, rson); 58 else return Query(x, y, lson) + Query(x, y, rson); 59 } 60 void Change(int x, int y, int l, int r, int rt) { 61 int mid = (l + r) >> 1; 62 if (x <= l && r <= y) {if(!done[rt]) dfs(l, r, rt);return;} 63 if (mid >= x) Change(x, y, lson); 64 if (mid + 1 <= y) Change(x, y, rson); 65 Update(rt); 66 } 67 }seg; 68 int main() { 69 //file("1"); 70 int CAS = 1, q, x, y, z; 71 while (scanf("%d", &n) == 1) { 72 For(i, n) scanf(LLD, &a[i]); 73 seg.build(1, n, 1); 74 printf("Case #%d:\n", CAS++); 75 scanf("%d", &q); 76 For(i, q) { 77 scanf("%d%d%d", &z, &x, &y); if (x > y) swap(x, y); 78 if (z == 0) seg.Change(x, y, 1, n, 1); 79 else printf(LLD "\n", seg.Query(x, y, 1, n, 1)); 80 } 81 printf("\n"); 82 } 83 return 0; 84 }
GSS5
Can you answer these queries V : http://www.spoj.com/problems/GSS5/
考虑两种情况:
1、两个区间隔开-> [x1,y1].....[x2,y2],所以[y1,x2]这段区间是必须计算的,然后计算出y1为右端店向左的左区间最大子序和、x2为左端点向右的最大子序和。
2、两个区间交错-> [x1,.....[x2,y1],.....y2],我们分3种情况讨论:
1)x1<=i<=x2, x2<=j<=y2:left[x1, x2-1]+a[x2]+right[x2+1, y2]
2)x2<=i<=y1, y1<=j<=y2:left[x1, y1-1]+a[y1]+right[y1+1, y2]
3)x2<=i<=j<=y1:tot[x1, y1]
注:三个标记:tot(区间最大子序和),left(从区间左端开始向右的最大子序和),right(从区间右端开始向左的最大子序和)
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 10010 5 #define L rt << 1 6 #define R rt << 1 | 1 7 #define lson l, mid, rt << 1 8 #define rson mid + 1, r, rt << 1 | 1 9 #define INF 0x3f3f3f3f 10 #define For(i, n) for (int i = 1; i <= n; i++) 11 using namespace std; 12 int n, sum[maxn], a[maxn]; 13 struct SegmentTree { 14 int tot[maxn << 2], left[maxn << 2], right[maxn << 2]; 15 void Update(int l, int r, int rt) { 16 int mid = (l + r) >> 1; 17 tot[rt] = max(tot[L], tot[R]); tot[rt] = max(tot[rt], right[L] + left[R]); 18 left[rt] = max(left[L], sum[mid] - sum[l - 1] + left[R]); 19 right[rt] = max(right[R], sum[r] - sum[mid] + right[L]); 20 } 21 void build(int l, int r, int rt) { 22 int mid = (l + r) >> 1; 23 if (l == r) { 24 tot[rt] = left[rt] = right[rt] = a[l]; 25 return; 26 } 27 build(lson), build(rson), Update(l, r, rt); 28 } 29 int Query(int flag, int x, int y, int &ans, int l, int r, int rt) { 30 int mid = (l + r) >> 1; 31 if (x <= l && r <= y) { 32 ans = max(ans, tot[rt]); 33 if (flag) return right[rt]; else return left[rt]; 34 } 35 if (mid >= y) return Query(0, x, y, ans, lson); else if (mid + 1 <= x) return Query(1, x, y, ans, rson); 36 int ln = Query(1, x, y, ans, lson), rn = Query(0, x, y, ans, rson); 37 ans = max(ans, ln + rn); 38 if (flag) return max(right[R], sum[r] - sum[mid] + ln); else return max(left[L], sum[mid] - sum[l - 1] + rn); 39 } 40 void Search(int flag, int x, int y, int &ans, int l, int r, int rt) { 41 int mid = (l + r) >> 1; 42 if (x <= l && r <= y) { 43 if (flag) ans = max(ans, sum[y] - sum[r] + right[rt]); else ans = max(ans, sum[l - 1] - sum[x - 1] + left[rt]); 44 return; 45 } 46 if (mid >= x) Search(flag, x, y, ans, lson); 47 if (mid + 1 <= y) Search(flag, x, y, ans, rson); 48 } 49 void init() { 50 scanf("%d", &n); 51 sum[0] = 0; For(i, n) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i]; 52 build(1, n, 1); 53 } 54 }seg; 55 56 int main() { 57 int CAS; scanf("%d", &CAS); 58 while (CAS--) { 59 seg.init(); 60 int q, ans, t1, t2, x1, x2, y1, y2; scanf("%d", &q); 61 For(i, q) { 62 scanf("%d%d%d%d", &x1, &y1, &x2, &y2); 63 if (y1 < x2) { 64 t1 = t2 = -INF; 65 seg.Search(1, x1, y1, t1, 1, n, 1); 66 seg.Search(0, x2, y2, t2, 1, n, 1); 67 printf("%d\n", t1 + t2 + sum[x2 - 1] - sum[y1]); 68 } 69 else { 70 ans = -INF; 71 seg.Query(0, x2, y1, ans, 1, n, 1); 72 t1 = t2 = -INF; 73 seg.Search(1, x1, y1, t1, 1, n, 1); 74 seg.Search(0, y1, y2, t2, 1, n, 1); 75 ans = max(ans, t1 + t2 - a[y1]); 76 t1 = t2 = -INF; 77 seg.Search(1, x1, x2, t1, 1, n, 1); 78 seg.Search(0, x2, y2, t2, 1, n, 1); 79 ans = max(ans, t1 + t2 - a[x2]); 80 printf("%d\n", ans); 81 } 82 } 83 } 84 return 0; 85 }
GSS6
Can you answer these queries VI : http://www.spoj.com/problems/GSS6/
呃,就是有插入,删除,修改操作,其他的区间最大子序和就向前几题那样处理。 我为了方便,弄了一颗平衡树,结果巨慢巨卡, T了好几次后加了读入优化,勉强AC。囧
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 #include <string> 4 #define maxn 210005 5 #define INF 0x3f3f3f3f 6 #define For(i, n) for (int i = 1; i <= n; i++) 7 #define L ch[x][0] 8 #define R ch[x][1] 9 #define lson l, mid - 1, x 10 #define rson mid + 1, r, x 11 using namespace std; 12 int n; 13 struct SplayTree { 14 int sz[maxn], pre[maxn], val[maxn], cnt[maxn], ch[maxn][2], left[maxn], right[maxn], sum[maxn], tot[maxn], a[maxn], rt, top; 15 void up(int x) { 16 sz[x] = sz[L] + sz[R] + 1; 17 sum[x] = sum[L] + sum[R] + val[x]; 18 tot[x] = max(right[L], 0) + val[x] + max(left[R], 0); tot[x] = max(tot[x], max(tot[L], tot[R])); 19 left[x] = max(left[L], sum[L] + val[x] + max(left[R], 0)); 20 right[x] = max(right[R], sum[R] + val[x] + max(right[L], 0)); 21 } 22 void Rotate(int x, int f) { 23 int y = pre[x]; 24 ch[y][!f] = ch[x][f]; 25 pre[ch[x][f]] = y; 26 pre[x] = pre[y]; 27 if (pre[x]) ch[pre[y]][ch[pre[y]][1] == y] = x; 28 ch[x][f] = y; 29 pre[y] = x; 30 up(y); 31 } 32 void Splay(int x, int goal) { 33 while (pre[x] != goal) { 34 if (pre[pre[x]] == goal) Rotate(x, ch[pre[x]][0] == x); 35 else { 36 int y = pre[x], z = pre[y], f = (ch[z][0] == y); 37 if (ch[y][f] == x) Rotate(x, !f), Rotate(x, f); else Rotate(y, f), Rotate(x, f); 38 } 39 } 40 up(x); 41 if (goal == 0) rt = x; 42 } 43 void RTO(int k, int goal) { 44 int x = rt; 45 while (k != sz[L] + 1) 46 if (k <= sz[L]) x = L; else k -= (sz[L] + 1), x = R; 47 Splay(x, goal); 48 } 49 void Newnode(int &x, int key) { 50 x = ++top; 51 sz[x] = 1; 52 val[x] = sum[x] = tot[x] = left[x] = right[x] = key; 53 L = R = 0; 54 } 55 void build(int &x, int l, int r, int f) { 56 int mid = (l + r) >> 1; 57 Newnode(x, a[mid]); 58 pre[x] = f; 59 if (l == r) return; 60 if (l < mid) build(L, lson); 61 if (mid < r) build(R, rson); 62 up(x); 63 } 64 void init() { 65 For(i, n) a[i] = INT(); 66 top = sz[0] = sum[0] = 0; 67 tot[0] = right[0] = left[0] = -INF; 68 Newnode(rt, 0), Newnode(ch[rt][1], 0); 69 pre[ch[rt][1]] = rt; 70 val[rt] = val[ch[rt][1]] = 0; 71 if (n) build(ch[ch[rt][1]][0], 1, n, ch[rt][1]); 72 up(ch[rt][1]), up(rt); 73 } 74 void Delete(int x) { 75 RTO(x, 0), RTO(x + 2, rt); 76 ch[ch[rt][1]][0] = 0; 77 up(ch[rt][1]), up(rt); 78 } 79 void Insert(int x, int y) { 80 RTO(x, 0), RTO(x + 1, rt); 81 Newnode(ch[ch[rt][1]][0], y); 82 pre[top] = ch[rt][1]; 83 up(ch[rt][1]), up(rt); 84 } 85 void Change(int x, int y) { 86 RTO(x + 1, 0); 87 val[rt] = y; 88 up(rt); 89 } 90 void Query(int l, int r) { 91 RTO(l, 0), RTO(r + 2, rt); 92 printf("%d\n", tot[ch[ch[rt][1]][0]]); 93 } 94 int INT() { 95 int ret, neg; char ch; 96 while (ch = getchar(), !isdigit(ch) && ch != '-'); 97 if (ch == '-') ret = 0, neg = 1; else ret = ch - '0', neg = 0; 98 while (ch = getchar(), isdigit(ch)) ret = ret * 10 + ch - '0'; 99 if (neg) return -ret; else return ret; 100 } 101 char CHAR() { 102 char ret; 103 while (ret = getchar(), !isalpha(ret)); 104 return ret; 105 } 106 void solve() { 107 int q, x, y; char op; 108 init(); 109 q = INT(); 110 For(i, q) { 111 op = CHAR(); 112 if (op == 'D') x = INT(), Delete(x); 113 else { 114 x = INT(), y = INT(); 115 if (op == 'I') Insert(x, y); else if (op == 'R') Change(x, y); else Query(x, y); 116 } 117 } 118 } 119 }spt; 120 int main() { 121 while (scanf("%d", &n) == 1) { 122 spt.solve(); 123 } 124 return 0; 125 }
GSS7
Can you answer these queries VII : http://www.spoj.com/problems/GSS7/
(呃。改天写吧,又囧。) srO zhonghaoxi Orz
I come, I see, I conquer!