【SPOJ】GSS总结

首先Orz zhonghaoxi找的的神题

GSS1 

Can you answer these queries I : http://www.spoj.com/problems/GSS1/

求区间最大子序和

考虑记录三个标记:tot(区间最大子序和),left(从区间左端开始向右的最大子序和),right(从区间右端开始向左的最大子序和)

Code:

GSS1_Code
 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:

GSS2_Code
 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:

GSS3_Code
 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:

GSS4_Code
 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:

GSS5_Code
 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:

GSS6_Code
  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

 

posted @ 2013-02-26 22:44  Joker0429  阅读(749)  评论(1编辑  收藏  举报