其他分享
首页 > 其他分享> > 毒瘤分块题

毒瘤分块题

作者:互联网

[Ynoi]2018 末日时...

好了,这题上来想构造一种新型的线段树,维护前缀,但后来发现最大字段和的性质太毒瘤了,然后直接自闭。

只好进入题解,看了一下shadowice的题解

哇shadowice太神仙了

闵可夫斯基珂并凸包

然后学了一下闵可夫斯基珂并凸包

主要讲如何快速合并凸包A,B

我们先求出点集A的上凸壳和点集B的上凸壳

然后构造一个网格图

接下来我们维护两个指针i,j表示在网格图上走到了(i,j)这个点

首先先将(1,1)加入点集

然后选择点(i+1,j)与(i,j)的斜率和点(i,j+1)与点(i,j)间的斜率较大的一组走

如果一侧已经无路可走就一直沿着另一侧走到底

合并完成

Jarvis水平步进法求凸包

1 找到位于最低最左边的点$p_0$,最高最右边的点$p_k$,则此两点必为凸包上的点。

2 对逆时针方向排列的顶点序列按$p_0$->$p_k$构造右链,左链。

3 设定一个栈,先将$p_0$入栈,对其他的点依据相对于栈顶元素的最小极角,并距离最远的点入栈,左链同理。

  求相对于栈顶元素的最小极角

  设$p_{top}$为最高点,$p_0$位栈顶元素;

  只要栈顶元素不是$p_{top}$,循环做以下工作:

  依次考查其他的点$p_i$,是否有相对于$p_{top}$的最小极角

贴个代码:基本上完全照着shadowice巨佬打的QAQ

//refer to shadowice1984's solution

//Compiler optimization
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")

#include <cstdio>
//type define
#define ll long long
//function define
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
//NUM define
const ll _MIN = (-(1ll << 47));
#define MAXN 100010
#define BLK_SIZE 110
#define BLK_NUM 1005

inline int readInt(){
    int x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

inline ll readLL(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

struct Point{
    ll x, y;  
};

Point operator + (const Point &a, const Point &b){
    return (Point){a.x + b.x, a.y + b.y};
}

inline bool CompVal(const Point &a, const Point &b, const ll &c){
    return ((b.x - a.x) * c >= b.y - a.y);
}

inline bool Comp3(const Point &a, const Point &b, const Point &c){
    return ((a.x - b.x) * (a.y - c.y) >= (a.y - b.y) * (a.x - c.x));
}

inline bool Comp4(const Point &a, const Point &b, const Point &c, const Point &d){
    return ((a.x - b.x) * (c.y - d.y) >= (a.y - b.y) * (c.x - d.x));
}

struct MSS{
    ll sum, l, r, ans;
};

MSS operator + (const MSS &a, const MSS &b){
    return (MSS){a.sum + b.sum, max(a.sum + b.l, a.l), max(a.r + b.sum, b.r), max(a.r + b.l, max(a.ans, b.ans))};
}

Point stk[BLK_SIZE + 1];
ll asum[BLK_SIZE + 1];

void getCH(Point *stk, int &top){
    //get convex hull
    int i, r;
    for(i = 2, r = top, top = 1; i <= r; ++i){
        while(top > 1 && Comp3(stk[top - 1], stk[top], stk[i]))
            --top;
        stk[++top] = stk[i];
    }
}

inline void insert(const Point &a){
    stk[a.x].y = max(stk[a.x].y, a.y);
}

struct Block{
    //threshold of caculate directly
    #define direct_ts 16
    //Member in long long
    ll a[BLK_SIZE + 1], add_val;
    ll thre_val;
    //Member in int
    int sz;
        //pre-[pre-suf-ans]
    int p1, p2, p3;
        //suf-[pr-suf-ans]
    int s1, s2, s3;
    //Member in MSS
    MSS val;
    //Membet in Point
    Point ans[BLK_SIZE + 1];
        // prefix           suffix 
    Point pre[BLK_SIZE + 1], suf[BLK_SIZE + 1];
    //Member in bool
    bool flg;
    //Functions
        //caculate directly 
    inline int sol_direct(int l, int r){
        ll tot = 0;
        for(int i = l + 1; i <= r; ++i)
            tot += a[i], ans[i] = (Point){i - l, tot};
        for(int i = l + 2; i <= r; ++i){
            tot = 0;
            Point* _new = ans + l + 1;
            for(int j = i; j <= r; ++j, ++_new)
                tot += a[j], _new->y = max(_new->y, tot);
        }
        s3 = r - l;
        getCH(ans + l, s3);
        return s3;
    }
        //caculate
    int sol(int l, int r){
        if(r - l < thre_val)
            return 0;
        if(r - l <= direct_ts)
            return sol_direct(l, r);
        int mid = (l + r) >> 1;
        int resl = sol(l, mid), resr = sol(mid, r);
        for(int i = 1; i <= r - l; ++i)
            stk[i] = (Point){i, _MIN};
        for(int i = l + 1; i <= l + resl; ++i)
            insert(ans[i]);
        for(int i = mid + 1; i <= mid + resr; ++i)
            insert(ans[i]);
        ll tot = 0;
        s1 = 0;
        for(int i = mid + 1; i <= r; ++i)
            ++s1, tot += a[i], pre[s1] = (Point){s1, tot};
        getCH(pre, s1);
        tot = 0, s2 = 0;
        for(int i = mid; i > l; --i)
            ++s2, tot += a[i], suf[s2] = (Point){s2, tot};
        getCH(suf, s2);
        //merge Convex Hull
            //go both direction
        int i = 1, j = 1;
        insert(pre[i] + suf[j]);
        for(; i != s1 && j != s2;){
            if (Comp4(pre[i], pre[i + 1], suf[j], suf[j + 1]))
                ++j;
            else
                ++i;
            insert(pre[i] + suf[j]);
        }
            //go along one direction
        if(i != s1)
            for(++i; i <= s1; ++i)
                insert(pre[i] + suf[j]);
        if(j != s2)
            for(++j; j <= s2; ++j)
                insert(pre[i] + suf[j]);
        s3 = r - l;
        getCH(stk, s3);
        for(int i = 1; i <= s3; ++i)
            ans[l + i] = stk[i];
        return s3;
    }
    inline void movP(Point *a, int &pos, int &t){
        while(pos != t)
            if(CompVal(a[pos], a[pos + 1], -add_val))
                break;
            else
                ++pos;
    }
    void build(){
        //Make convex hull
        for (int i = 1; i <= sz; ++i)
            a[i] += add_val;
        add_val = 0;
        if (!flg){
            //refresh flg
            flg = 1;
            for (int i = 1; i <= sz; ++i)
                flg = flg && (a[i] >= 0ll);
        }
        if (flg){
            val.sum = 0;
            for (int i = 1; i <= sz; ++i)
                val.sum += a[i];
            val.l = val.r = val.ans = val.sum;
            return ;
        }
        thre_val = ans[p3].x, sol(0ll, sz);
        ll tot = 0ll; s1 = 0ll;
        for (int i = 1; i <= sz; ++i)
            ++s1, tot += a[i], pre[s1] = (Point){s1, tot};
        getCH(pre, s1);
        tot = 0ll, s2 = 0ll;
        for (int i = sz; i >= 1; --i)
            ++s2, tot += a[i], suf[s2] = (Point){s2, tot};
        getCH(suf, s2);
        p1 = 1, movP(pre, p1, s1);
        p2 = 1, movP(suf, p2, s2);
        p3 = 1, movP(ans, p3, s3);
        //refresh flg again
        flg &= (bool)((p1 == s1) && (p2 == s2) && (p3 == s3));
        //refresh val
        val = (MSS){tot, max(pre[p1].y, 0ll), max(suf[p2].y, 0ll), max(ans[p3].y, 0ll)};
    }
    void add(ll x){
        if (flg){
            add_val += x;
            val.sum += sz * x;
            val.l = val.r = val.ans = val.sum;
            return ;
        }
        add_val += x;
        movP(pre, p1, s1), movP(suf, p2, s2), movP(ans, p3, s3);
        //refresh flg
        flg &= (bool)((p1 == s1) && (p2 == s2) && (p3 == s3));
        val = (MSS){val.sum + sz * x, max(pre[p1].x * add_val + pre[p1].y, 0ll), max(suf[p2].x * add_val + suf[p2].y, 0ll), max(ans[p3].x * add_val + ans[p3].y, 0ll)};
    }
    inline ll cac_direct(int l, int r){
        //caculate directly
        int a_end = 0;
        for(int i = l; i <= r; ++i)
            asum[++a_end] = a[i] + add_val;
        for(int i = 1; i <= a_end; ++i)
            asum[i] += asum[i - 1];
        ll _min = 0, res = 0;
        for(int i = 1; i <= a_end; ++i)
            res = max(res, asum[i] - _min), _min = min(_min, asum[i]);
        return res;
    }
    MSS cac(int l, int r){
        MSS res = (MSS){0, 0, 0, 0};
        int a_end = 0;
        for (int i = l; i <= r; ++i)
            asum[++a_end] = a[i] + add_val;
        for(int i = 1; i <= a_end; ++i)
            res.sum += asum[i], res.l = max(res.l, res.sum);
        res.sum = 0;
        for(int i = a_end; i >= 1; --i)
            res.sum += asum[i], res.r = max(res.r, res.sum);
        for(int i = 1; i <= a_end; ++i)
            asum[i] += asum[i - 1];
        ll _min = 0;
        for(int i = 1; i <= a_end; ++i)
            res.ans = max(res.ans, asum[i] - _min), _min = min(_min, asum[i]);
        return res;
    }
    #undef direct_ts
} blk[BLK_NUM];

int belong_blk[MAXN], pos_in_blk[MAXN];

int main(){
    int n = readInt(), m = readInt();
    for (register int i = 0, j = 1; i < n; i += BLK_SIZE, ++j){
        for (register int k = 1; (k <= BLK_SIZE) && (i + k <= n); ++k){
            blk[j].a[k] = readLL(), belong_blk[i + k] = j, pos_in_blk[i + k] = k;
        }
        blk[j].sz = min(BLK_SIZE, n - i), blk[j].build();
    }
    int op, l, r;
    ll x;
    MSS res;
    for (register int i = 0; i < m; ++i){
        op = readInt(), l = readInt(), r = readInt();
        if (op == 1){
            x = readLL();
            if (belong_blk[l] == belong_blk[r]){
                for (int j = pos_in_blk[l]; j <= pos_in_blk[r]; ++j)
                    blk[belong_blk[l]].a[j] += x;
                blk[belong_blk[l]].build();
            }
            else{
                for (int j = pos_in_blk[l]; j <= blk[belong_blk[l]].sz; ++j)
                    blk[belong_blk[l]].a[j] += x;
                blk[belong_blk[l]].build();
                for (int j = belong_blk[l] + 1; j < belong_blk[r]; ++j)
                    blk[j].add(x);
                for (int j = 1; j <= pos_in_blk[r]; ++j)
                    blk[belong_blk[r]].a[j] += x;
                blk[belong_blk[r]].build();
            }
        }
        else{
            if (belong_blk[l] == belong_blk[r])
                printf("%lld\n", blk[belong_blk[l]].cac_direct(pos_in_blk[l], pos_in_blk[r]));
            else{
                res = blk[belong_blk[l]].cac(pos_in_blk[l], blk[belong_blk[l]].sz);
                for (register int j = belong_blk[l] + 1; j < belong_blk[r]; ++j)
                    res = res + blk[j].val;
                res = res + blk[belong_blk[r]].cac(1, pos_in_blk[r]);
                printf("%lld\n", res.ans);
            }
        }
    }
    return 0;
}

 

//refer to shadowice1984's solution
//Compiler optimization#pragma GCC optimize(3)#pragma GCC optimize("Ofast")
#include <cstdio>//type define#define ll long long//function define#define min(a,b) ((a<b)?a:b)#define max(a,b) ((a>b)?a:b)//NUM defineconst ll _MIN = (-(1ll << 47));#define MAXN 100010#define BLK_SIZE 110#define BLK_NUM 1005
inline int readInt(){    int x = 0; int zf = 1; char ch = ' ';    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();    if (ch == '-') zf = -1, ch = getchar();    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
inline ll readLL(){    ll x = 0; int zf = 1; char ch = ' ';    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();    if (ch == '-') zf = -1, ch = getchar();    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
struct Point{    ll x, y;  };
Point operator + (const Point &a, const Point &b){    return (Point){a.x + b.x, a.y + b.y};}
inline bool CompVal(const Point &a, const Point &b, const ll &c){    return ((b.x - a.x) * c >= b.y - a.y);}
inline bool Comp3(const Point &a, const Point &b, const Point &c){    return ((a.x - b.x) * (a.y - c.y) >= (a.y - b.y) * (a.x - c.x));}
inline bool Comp4(const Point &a, const Point &b, const Point &c, const Point &d){    return ((a.x - b.x) * (c.y - d.y) >= (a.y - b.y) * (c.x - d.x));}
struct MSS{    ll sum, l, r, ans;};
MSS operator + (const MSS &a, const MSS &b){    return (MSS){a.sum + b.sum, max(a.sum + b.l, a.l), max(a.r + b.sum, b.r), max(a.r + b.l, max(a.ans, b.ans))};}
Point stk[BLK_SIZE + 1];ll asum[BLK_SIZE + 1];
void getCH(Point *stk, int &top){    //get convex hull    int i, r;    for(i = 2, r = top, top = 1; i <= r; ++i){        while(top > 1 && Comp3(stk[top - 1], stk[top], stk[i]))            --top;        stk[++top] = stk[i];    }}
inline void insert(const Point &a){    stk[a.x].y = max(stk[a.x].y, a.y);}
struct Block{    //threshold of caculate directly    #define direct_ts 16    //Member in long long    ll a[BLK_SIZE + 1], add_val;    ll thre_val;    //Member in int    int sz;        //pre-[pre-suf-ans]    int p1, p2, p3;        //suf-[pr-suf-ans]    int s1, s2, s3;    //Member in MSS    MSS val;    //Membet in Point    Point ans[BLK_SIZE + 1];        // prefix           suffix     Point pre[BLK_SIZE + 1], suf[BLK_SIZE + 1];    //Member in bool    bool flg;    //Functions        //caculate directly     inline int sol_direct(int l, int r){        ll tot = 0;        for(int i = l + 1; i <= r; ++i)            tot += a[i], ans[i] = (Point){i - l, tot};        for(int i = l + 2; i <= r; ++i){            tot = 0;            Point* _new = ans + l + 1;            for(int j = i; j <= r; ++j, ++_new)                tot += a[j], _new->y = max(_new->y, tot);        }        s3 = r - l;        getCH(ans + l, s3);        return s3;    }        //caculate    int sol(int l, int r){        if(r - l < thre_val)            return 0;        if(r - l <= direct_ts)            return sol_direct(l, r);        int mid = (l + r) >> 1;        int resl = sol(l, mid), resr = sol(mid, r);        for(int i = 1; i <= r - l; ++i)            stk[i] = (Point){i, _MIN};        for(int i = l + 1; i <= l + resl; ++i)            insert(ans[i]);        for(int i = mid + 1; i <= mid + resr; ++i)            insert(ans[i]);        ll tot = 0;        s1 = 0;        for(int i = mid + 1; i <= r; ++i)            ++s1, tot += a[i], pre[s1] = (Point){s1, tot};        getCH(pre, s1);        tot = 0, s2 = 0;        for(int i = mid; i > l; --i)            ++s2, tot += a[i], suf[s2] = (Point){s2, tot};        getCH(suf, s2);        //merge Convex Hull            //go both direction        int i = 1, j = 1;        insert(pre[i] + suf[j]);        for(; i != s1 && j != s2;){            if (Comp4(pre[i], pre[i + 1], suf[j], suf[j + 1]))                ++j;            else                ++i;            insert(pre[i] + suf[j]);        }            //go along one direction        if(i != s1)            for(++i; i <= s1; ++i)                insert(pre[i] + suf[j]);        if(j != s2)            for(++j; j <= s2; ++j)                insert(pre[i] + suf[j]);        s3 = r - l;        getCH(stk, s3);        for(int i = 1; i <= s3; ++i)            ans[l + i] = stk[i];        return s3;    }    inline void movP(Point *a, int &pos, int &t){        while(pos != t)            if(CompVal(a[pos], a[pos + 1], -add_val))                break;            else                ++pos;    }    void build(){        //Make convex hull        for (int i = 1; i <= sz; ++i)            a[i] += add_val;        add_val = 0;        if (!flg){            //refresh flg            flg = 1;            for (int i = 1; i <= sz; ++i)                flg = flg && (a[i] >= 0ll);        }        if (flg){            val.sum = 0;            for (int i = 1; i <= sz; ++i)                val.sum += a[i];            val.l = val.r = val.ans = val.sum;            return ;        }        thre_val = ans[p3].x, sol(0ll, sz);        ll tot = 0ll; s1 = 0ll;        for (int i = 1; i <= sz; ++i)            ++s1, tot += a[i], pre[s1] = (Point){s1, tot};        getCH(pre, s1);        tot = 0ll, s2 = 0ll;        for (int i = sz; i >= 1; --i)            ++s2, tot += a[i], suf[s2] = (Point){s2, tot};        getCH(suf, s2);        p1 = 1, movP(pre, p1, s1);        p2 = 1, movP(suf, p2, s2);        p3 = 1, movP(ans, p3, s3);        //refresh flg again        flg &= (bool)((p1 == s1) && (p2 == s2) && (p3 == s3));        //refresh val        val = (MSS){tot, max(pre[p1].y, 0ll), max(suf[p2].y, 0ll), max(ans[p3].y, 0ll)};    }    void add(ll x){        if (flg){            add_val += x;            val.sum += sz * x;            val.l = val.r = val.ans = val.sum;            return ;        }        add_val += x;        movP(pre, p1, s1), movP(suf, p2, s2), movP(ans, p3, s3);        //refresh flg        flg &= (bool)((p1 == s1) && (p2 == s2) && (p3 == s3));        val = (MSS){val.sum + sz * x, max(pre[p1].x * add_val + pre[p1].y, 0ll), max(suf[p2].x * add_val + suf[p2].y, 0ll), max(ans[p3].x * add_val + ans[p3].y, 0ll)};    }    inline ll cac_direct(int l, int r){        //caculate directly        int a_end = 0;        for(int i = l; i <= r; ++i)            asum[++a_end] = a[i] + add_val;        for(int i = 1; i <= a_end; ++i)            asum[i] += asum[i - 1];        ll _min = 0, res = 0;        for(int i = 1; i <= a_end; ++i)            res = max(res, asum[i] - _min), _min = min(_min, asum[i]);        return res;    }    MSS cac(int l, int r){        MSS res = (MSS){0, 0, 0, 0};        int a_end = 0;        for (int i = l; i <= r; ++i)            asum[++a_end] = a[i] + add_val;        for(int i = 1; i <= a_end; ++i)            res.sum += asum[i], res.l = max(res.l, res.sum);        res.sum = 0;        for(int i = a_end; i >= 1; --i)            res.sum += asum[i], res.r = max(res.r, res.sum);        for(int i = 1; i <= a_end; ++i)            asum[i] += asum[i - 1];        ll _min = 0;        for(int i = 1; i <= a_end; ++i)            res.ans = max(res.ans, asum[i] - _min), _min = min(_min, asum[i]);        return res;    }    #undef direct_ts} blk[BLK_NUM];
int belong_blk[MAXN], pos_in_blk[MAXN];
int main(){    int n = readInt(), m = readInt();    for (register int i = 0, j = 1; i < n; i += BLK_SIZE, ++j){        for (register int k = 1; (k <= BLK_SIZE) && (i + k <= n); ++k){            blk[j].a[k] = readLL(), belong_blk[i + k] = j, pos_in_blk[i + k] = k;        }        blk[j].sz = min(BLK_SIZE, n - i), blk[j].build();    }    int op, l, r;    ll x;    MSS res;    for (register int i = 0; i < m; ++i){        op = readInt(), l = readInt(), r = readInt();        if (op == 1){            x = readLL();            if (belong_blk[l] == belong_blk[r]){                for (int j = pos_in_blk[l]; j <= pos_in_blk[r]; ++j)                    blk[belong_blk[l]].a[j] += x;                blk[belong_blk[l]].build();            }            else{                for (int j = pos_in_blk[l]; j <= blk[belong_blk[l]].sz; ++j)                    blk[belong_blk[l]].a[j] += x;                blk[belong_blk[l]].build();                for (int j = belong_blk[l] + 1; j < belong_blk[r]; ++j)                    blk[j].add(x);                for (int j = 1; j <= pos_in_blk[r]; ++j)                    blk[belong_blk[r]].a[j] += x;                blk[belong_blk[r]].build();            }        }        else{            if (belong_blk[l] == belong_blk[r])                printf("%lld\n", blk[belong_blk[l]].cac_direct(pos_in_blk[l], pos_in_blk[r]));            else{                res = blk[belong_blk[l]].cac(pos_in_blk[l], blk[belong_blk[l]].sz);                for (register int j = belong_blk[l] + 1; j < belong_blk[r]; ++j)                    res = res + blk[j].val;                res = res + blk[belong_blk[r]].cac(1, pos_in_blk[r]);                printf("%lld\n", res.ans);            }        }    }    return 0;}

标签:suf,ch,val,Point,int,s2,分块,毒瘤
来源: https://www.cnblogs.com/linzhengmin/p/10830454.html