zoukankan      html  css  js  c++  java
  • SPOJ GSS5

    我又来水数据结构了。

    按照套路,线段树上要维护四个值$res, sum, suf, pre$,分别表示当前区间的最大子段和,总和,强制选右端点的最大子段和,强制选左端点的最大子段和,那么更新的时候就有:

        inline void up(int p) {
            sum(p) = sum(lc) + sum(rc);     
            suf(p) = max(suf(rc), sum(rc) + suf(lc)); 
            pre(p) = max(pre(lc), sum(lc) + pre(rc));
            res(p) = max(res(lc), res(rc), suf(lc) + pre(rc));
        }

    注意查询的时候返回空结点的$suf,pre,res$都是$-inf$。

    如果询问$xa, ya, xb, yb$满足$ya < xb$,那么答案就为$sum(ya, xb) + max(0, suf(xa, ya - 1)) + max(0, pre(xb + 1, yb))$;如果不满足,那么答案在$res(xb, ya)$、$pre(ya + 1, yb) + suf(xb, ya)$、$pre(xb, ya) + suf(xa, xb - 1)$、$sum(xb, ya) + max(0, suf(xa, xb - 1)) + max(0, pre(ya + 1, yb))$取个最大。

    画个图理解一下就好啦。

    时间复杂度为$O(Tnlogn)$,虽然常数很大,但是跑个$10000$完全没问题。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int N = 1e4 + 5;
    const int inf = 1 << 30;
    
    int testCase, n, qn, a[N];
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline int max(int x, int y) {
        return x > y ? x : y;
    }
    
    inline int max(int x, int y, int z) {
        return max(x, max(y, z));
    }
    
    inline void chkMax(int &x, int y) {
        if(y > x) x = y;
    }
    
    namespace SegT {
        struct Node {
            int lc, rc, res, suf, pre, sum;
    
            inline void init() {
                res = suf = pre = -inf, sum = 0;
            }
    
        } s[N << 2];
    
        #define lc p << 1
        #define rc p << 1 | 1
        #define res(p) s[p].res
        #define suf(p) s[p].suf
        #define pre(p) s[p].pre
        #define sum(p) s[p].sum
        #define mid ((l + r) >> 1)
    
        inline void up(int p) {
            sum(p) = sum(lc) + sum(rc);     
            suf(p) = max(suf(rc), sum(rc) + suf(lc)); 
            pre(p) = max(pre(lc), sum(lc) + pre(rc));
            res(p) = max(res(lc), res(rc), suf(lc) + pre(rc));
        }
    
        void build(int p, int l, int r) {
            if(l == r) {
                sum(p) = res(p) = suf(p) = pre(p) = a[l];
                return;
            }
    
            build(lc, l, mid);
            build(rc, mid + 1, r);
            up(p);
        }
    
        Node query(int p, int l, int r, int x, int y) {
            if(x > y) return (Node) {0, 0, -inf, -inf, -inf, 0};
            if(x <= l && y >= r) return s[p];
    
            Node ln, rn, res;
            ln.init(), rn.init(), res.init();
    
            if(x <= mid) ln = query(lc, l, mid, x, y);
            if(y > mid) rn = query(rc, mid + 1, r, x, y);
    
            res.sum = ln.sum + rn.sum;
            res.suf = max(rn.suf, ln.suf + rn.sum);
            res.pre = max(ln.pre, rn.pre + ln.sum);
            res.res = max(ln.res, rn.res, ln.suf + rn.pre);
    
            return res;
        }
    
    } using namespace SegT;
    
    inline void solve(int xa, int ya, int xb, int yb) {
        int res;
        if(ya < xb) {
            res = query(1, 1, n, ya, xb).sum;
            res += max(0, query(1, 1, n, xa, ya - 1).suf);
            res += max(0, query(1, 1, n, xb + 1, yb).pre);
        } else {
            res = query(1, 1, n, xb, ya).res;
            chkMax(res, query(1, 1, n, ya + 1, yb).pre + query(1, 1, n, xb, ya).suf);
            chkMax(res, query(1, 1, n, xa, xb - 1).suf + query(1, 1, n, xb, ya).pre);
            chkMax(res, query(1, 1, n, xb, ya).sum + max(0, query(1, 1, n, xa, xb - 1).suf) + max(0, query(1, 1, n, ya + 1, yb).pre));
        }
    
        printf("%d
    ", res);
    }
    
    int main() {
        for(read(testCase); testCase--; ) {
            read(n);
            for(int i = 1; i <= n; i++) read(a[i]);
    
            build(1, 1, n);
    
            read(qn);
            for(int xa, ya, xb, yb; qn--; ) {
                read(xa), read(ya), read(xb), read(yb);
                solve(xa, ya, xb, yb);
            }
    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    列举ASP.NET 页面之间传递值的几种方式?
    Ajax 完整教程
    ajax 传值,Ajax: Asynchoronous Javascript and xml (异步的js和xml). 异步刷新,异步传递.替代表单提交数据,回调函数处理返回的数据
    Webform 翻页查询.最主要理解这一句代码 return _Context.ChinaStates.Skip((nowpage
    datalist 的用法。也是增删改查,但是比较智能。用数据绑定的方式,可以有不同的显示方法,下面是对一个表的增删改查的参考代码
    bzoj 2705: [SDOI2012]Longge的问题 歐拉函數
    bzoj 1096: [ZJOI2007]仓库建设 斜率優化
    HJA的异或值
    Contest 20140914 Mushroom写情书 字符串雙hash 後綴數組
    Contest 高数题 樹的點分治 樹形DP
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9880054.html
Copyright © 2011-2022 走看看