• bzoj4695 最假女选手


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4695

    【题解】

    SegmentTree beats!(见jiry_2论文/营员交流)

    考虑只有对p取max,区间加,查min/和怎么做。

    有一道类似的题,是取min,见hdu5306.

    按照segmentbeats这套理论,我们要维护最小值,最小值出现个数,次小值即可。

    每次区间对$p$取max,如果当前节点满足$min < p < sec$,那么打区间max标记,而且我们也可以很方便算出每个的改变量。

    标记下传的话考虑对于$x$的儿子,显然要么满足$p < min$,要么满足$min < p < sec$,直接维护即可。

    这里的标记我们不需要开一个tag存,我们只要判断是否满足$min < p < sec$就知道是否下传标记了。

    【考虑同时维护min/max的情况】

    按照segmentbeats这套理论,我们要维护最小值,最小值出现个数,次小值;最大值,最大值出现个数,次大值即可。

    对区间取min操作和上面说的取max操作类似,我们着重讨论标记下传问题。

    这里涉及到标记的叠加,稍加讨论下我们发现,只要判断$min < min_x < secmin$就知道是否要把$min_x$传给儿子;同理判断$secmax < max_x < max$就知道是否要把$max_x$传给儿子

    这里还涉及到一个问题:标记下传的先后顺序。

    考虑什么时候标记存在影响:因为标记都是对最大值和次大值,最小值和次小值之间的区间打的,其他都是暴力维护,所以只对区间长度小于等于2的情况产生影响

    稍加讨论我们发现,先传和后传是没有影响的。

    e.g. 区间 = $[3, 6]$

    父区间有标记:对于4取max,对于5取min

    那么显然没有影响,正常做即可。

    父区间有标记:对于5取max,对于4取min。

    我们发现,对于5取max的情况,父区间序列一定变成了$[5, ...]$,这时候再对4取min,不符合标记的性质了,所以不存在这种情况。

    复杂度:$O(nlog^2n)$,跑的和$O(nlogn)$差不多。

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int N = 5e5 + 10, SN = 1048576 + 5;
    const int mod = 1e9+7, inf = 1e9;
    
    inline int getint() {
        int x = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {
            if(ch == '-') f = 0;
            ch = getchar();
        }
        while(isdigit(ch)) {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }
        return f ? x : -x;
    }
    
    int n, a[N];
    struct node {
        int p, t, se;
        node () {}
        node (int p, int t, int se) : p(p), t(t), se(se) {}
        inline friend node combineMax(node a, node b) {
            node c;
            if(a.p < b.p) {
                c.p = b.p; c.t = b.t;
                c.se = max(a.p, b.se);
            } else if(a.p > b.p) {
                c.p = a.p; c.t = a.t;
                c.se = max(a.se, b.p);
            } else {
                c.p = a.p; c.t = a.t + b.t;
                c.se = max(a.se, b.se);
            }
            return c;
        }
        inline friend node combineMin(node a, node b) {
            node c;
            if(a.p > b.p) {
                c.p = b.p; c.t = b.t;
                c.se = min(a.p, b.se);
            } else if(a.p < b.p) {
                c.p = a.p; c.t = a.t;
                c.se = min(a.se, b.p);
            } else {
                c.p = a.p; c.t = a.t + b.t;
                c.se = min(a.se, b.se);
            }
            return c;
        }
        inline friend node operator + (node a, int p) {
            return node(a.p + p, a.t, a.se + p);
        }
    };
    
    struct SMTbeats {
        node mx[SN], mi[SN];
        int tag[SN]; ll s[SN];
        # define ls (x<<1)
        # define rs (x<<1|1)
        inline void up(int x) {
            mx[x] = combineMax(mx[ls], mx[rs]);
            mi[x] = combineMin(mi[ls], mi[rs]);
            s[x] = s[ls] + s[rs];
        }
        
        // a = max(a, t)
        inline void pushmax(int x, int l, int r, int p) {
            s[x] += 1ll * mi[x].t * (p - mi[x].p);
            mi[x].p = p; mx[x].p = max(mx[x].p, p);
            if(mi[x].p == mx[x].p) {
                mi[x].se = inf, mx[x].se = -inf;
                mi[x].t = mx[x].t = r-l+1;
                s[x] = 1ll * mi[x].p * (r-l+1);
            } else mx[x].se = max(mx[x].se, p);
        }
        // a = min(a, t)
        inline void pushmin(int x, int l, int r, int p) {
            s[x] += 1ll * mx[x].t * (p - mx[x].p);
            mx[x].p = p; mi[x].p = min(mi[x].p, p);
            if(mi[x].p == mx[x].p) {
                mi[x].se = inf, mx[x].se = -inf;
                mi[x].t = mx[x].t = r-l+1;
                s[x] = 1ll * mi[x].p * (r-l+1);
            } else mi[x].se = min(mi[x].se, p);
        }
        inline void pushtag(int x, int l, int r, int p) {
            tag[x] += p; s[x] += 1ll * (r-l+1) * p;
            mx[x] = mx[x] + p, mi[x] = mi[x] + p;
        }
        
        inline void down(int x, int l, int r) {
            int mid = l+r>>1;
            if(tag[x]) {
                pushtag(ls, l, mid, tag[x]); pushtag(rs, mid+1, r, tag[x]);
                tag[x] = 0;
            }    
            if(mx[ls].p > mx[x].p && mx[ls].se < mx[x].p) pushmin(ls, l, mid, mx[x].p);
            if(mx[rs].p > mx[x].p && mx[rs].se < mx[x].p) pushmin(rs, mid+1, r, mx[x].p);
            if(mi[ls].p < mi[x].p && mi[ls].se > mi[x].p) pushmax(ls, l, mid, mi[x].p);
            if(mi[rs].p < mi[x].p && mi[rs].se > mi[x].p) pushmax(rs, mid+1, r, mi[x].p);    
        }
        
        inline void build(int x, int l, int r) {
            tag[x] = 0;
            if(l == r) {
                mx[x].p = mi[x].p = s[x] = a[l], mx[x].t = mi[x].t = 1, mx[x].se = -inf, mi[x].se = inf;
                return ;
            }
            int mid = l+r>>1;
            build(ls, l, mid);
            build(rs, mid+1, r);
            up(x);
        }
        
        inline void edt(int x, int l, int r, int L, int R, int p) {
            if(L <= l && r <= R) {
                pushtag(x, l, r, p);
                return ;
            }
            down(x, l, r);
            int mid = l+r>>1;
            if(L <= mid) edt(ls, l, mid, L, R, p);
            if(R > mid) edt(rs, mid+1, r, L, R, p);
            up(x);
        }
        
        inline void edtmin(int x, int l, int r, int L, int R, int p) {
            if(mx[x].p <= p) return ;
            if(L <= l && r <= R && mx[x].se < p) {
                pushmin(x, l, r, p);
                return ;
            }
            down(x, l, r);
            int mid = l+r>>1;
            if(L <= mid) edtmin(ls, l, mid, L, R, p);
            if(R > mid) edtmin(rs, mid+1, r, L, R, p);
            up(x);
        }
        
        inline void edtmax(int x, int l, int r, int L, int R, int p) {
            if(mi[x].p >= p) return ;
            if(L <= l && r <= R && mi[x].se > p) {
                pushmax(x, l, r, p);
                return ;
            }
            down(x, l, r);
            int mid = l+r>>1;
            if(L <= mid) edtmax(ls, l, mid, L, R, p);
            if(R > mid) edtmax(rs, mid+1, r, L, R, p);
            up(x);
        }
        
        inline int gmax(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return mx[x].p;
            down(x, l, r);
            int mid = l+r>>1, ret = -inf;
            if(L <= mid) ret = max(ret, gmax(ls, l, mid, L, R));
            if(R > mid) ret = max(ret, gmax(rs, mid+1, r, L, R));
            return ret;
        }
        
        inline int gmin(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return mi[x].p;
            down(x, l, r);
            int mid = l+r>>1, ret = inf;
            if(L <= mid) ret = min(ret, gmin(ls, l, mid, L, R));
            if(R > mid) ret = min(ret, gmin(rs, mid+1, r, L, R));
            return ret;
        }
        
        inline ll gsum(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return s[x];
            down(x, l, r);
            int mid = l+r>>1; ll ret = 0;
            if(L <= mid) ret += gsum(ls, l, mid, L, R);
            if(R > mid) ret += gsum(rs, mid+1, r, L, R);
            return ret;
        }
    
        inline void debug(int x, int l, int r) {
            printf("%d %d %d [%d %d %d] [%d %d %d] %I64d
    ", x, l, r, mx[x].p, mx[x].t, mx[x].se, mi[x].p, mi[x].t, mi[x].se, s[x]);
            if (l == r) return ;
            int mid = l+r>>1;
            debug(ls, l, mid);
            debug(rs, mid+1, r);
        }
        
        # undef ls
        # undef rs
    }T;
    
    
    
    int main() {
        n = getint();
        for (int i=1; i<=n; ++i) a[i] = getint();
        T.build(1, 1, n);
        int Q, op, l, r, x; cin >> Q;
        while(Q--) {
    //        T.debug(1, 1, n);
            op = getint(), l = getint(), r = getint();
            if(op == 1) {
                x = getint();
                T.edt(1, 1, n, l, r, x);
            } else if(op == 2) {
                x = getint();
                T.edtmax(1, 1, n, l, r, x);
            } else if(op == 3) {
                x = getint();
                T.edtmin(1, 1, n, l, r, x);
            } else if(op == 4) printf("%lld
    ", T.gsum(1, 1, n, l, r));
            else if(op == 5) printf("%d
    ", T.gmax(1, 1, n, l, r));
            else printf("%d
    ", T.gmin(1, 1, n, l, r));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    今天还做了点有意义的事
    读“记当年的公开课”
    无语
    小议如何控制学生机结束学生端多媒体控制平台程序
    今天去了中山
    Windows服务创建及安装
    SQL Server数据库表锁定原理以及如何解除表的锁定示例演示
    本地SQL脚本操作外部服务器结果集
    list.FindAll
    一个高效的数据分页的存储过程 可以轻松应付百万数据
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj4695.html
Copyright © 2020-2023  润新知