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\n", 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\n", T.gsum(1, 1, n, l, r));
        else if(op == 5) printf("%d\n", T.gmax(1, 1, n, l, r));
        else printf("%d\n", T.gmin(1, 1, n, l, r));
    }
    return 0;
}

时间: 2024-10-11 18:12:41

bzoj4695 最假女选手的相关文章

【bzoj4695】最假女选手

zcy的励志故事.jpg 傻逼zcy突然想立一个flag,写一个segment-tree-beats的题娱乐一下 于是他就想起了这道题. 他打算今晚写完 然后光是写他就写的头昏脑涨,还犯了询问写反这种傻逼错误 后来他发现调不出来了 然后调了快2h,写个暴力对拍才发现pushup写的是萎的. 这题其实就是很恶心的吧操作扔在一起 但是还是维护最大值,最大值出现次数,次大值能解决的问题. 标记合并的时候注意讨论下,细节有点多,样例比较彩笔 建议提交之前先测试所有操作或者跟暴力对拍. #include<

HDU4695 最假女选手(吉司机线段树)

本题原理和代码讲解会在近日放到b站,对题目解法不是很了解的同学可以关注b站 朝暮不思 #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<string> #include<cstring> #include<map> #include<set> using

真硅谷巨骗、假女版乔布斯覆灭记:4星|《坏血》

详尽还原所谓“女版乔布斯”的硅谷创业明星.独角兽公司希拉洛斯及其创始人伊丽莎白的发展与覆灭历史. 伊丽莎白精力充沛,充满梦想,崇拜并刻意模仿乔布斯.她在2002年被斯坦福录取,2003年秋天辍学创业,想发明一种薄薄的贴片,实时监测病人身体状况并实时治疗.她顺利筹到了启动资金,在公司启动后想法略有收敛,改为迷你生化仪+一滴血实时检测. 公司多次筹得巨额资金,并说服了沃尔格林连锁药店和西夫韦连锁零售店两个巨头跟其合作,在门店部署便捷一滴血检测仪. 实际上希拉洛斯的产品一直停留在原型阶段,从来不可用.

关于吉利线段树

引言 这玩意儿又称\(Segment\ Tree\ Beats\) .由吉老师.\(Picks\).美国队长三位知名毒瘤发明. 我的精神受到了污染...... 线段树简介 线段树什么的太难了,不是很会啊..... 线段树最强的地方在于,如果标记支持合并,那么我们就能够快速进行区间修改了. 一类特殊标记 维护这样一个标记\((a,b)\) ,表示\(x\to max(x + a , b)\) . 显然标记可合并:\((a,b) + (c,d) = (a + c , max(b + c , d))\

大海扬波,靠地球自转、潮汐和飓风

忠诚,就忠诚自己的土壤: 追求,就追求自己的理想. --引自友人的诗 这是一曲振奋人心的搏斗之歌.它的主旋律,就是祖国的荣誉高于一切! 人们把体育比喻为一个民族精神的橱窗.那么,就让我们打开中国女排这个小小的窗口,看一看我们中华民族应有的精神风貌吧! 挥动黄手绢唱的歌 公元一千九百七十七年深秋.苍茫的暮色,笼罩着日本的商业都市大阪. 中国女排姑娘们乘坐的大型轿车,顺着五光十色的街道缓缓向前行驶. 多彩的夜景,与中国姑娘们喜悦的心境是相吻合的.今晚,一九七七年世界杯排球赛进入最后一个高潮--发奖.

新手福利

之所以写这篇文章,是因为我在上周六的飞镖比赛中,输给了一个玩镖没有我久的女选手,不禁令我感叹,长江后浪推前浪.之前我们队与她所在的队伍在联赛中也有过碰面,那时候的她投掷其他区域都不怎么精准,唯独19特别好.但是今天再遇到她,已经全部区域都能很精准地命中了.虽然我觉得,也许再和她对战一局,我或许能够取得胜利,但是不得不承认,现在比我起步晚的飞镖爱好者越来越多,而实力在我之上的也大有人在了. 记得我刚玩飞镖时,指点我的是一个Rating7级的日本爷爷,那时候我也以他为榜样.但是几个月后,我就超过了他

网红淘宝店的成与败

近年来,随着直播的人气火热上升,越来越多的网红出现在我们的眼前.很多人都想成为网红,为什么呢?因为他们有人气,有喜欢自己的粉丝,而他们能通过这些粉丝和人气来获取利益,例如通过自己的人气接广告或卖东西给喜欢自己的粉丝.这就是为什么淘宝里有越来越多的网红店,他们通过自身的人气效应给自己打广告,在直播或博客中秀出自己店里的商品. 想要了解网红淘宝店的成与败,我们先来谈论网红淘宝店的运营方式.网红淘宝店当然老板是网红,但其实在幕后有一个操作团体,他们不仅起到封装网红的作用,还帮他们进货出货,网红只要负责

apio2017游记

//第一次写游记,只是流水账...结果好像确实只去游了…… day-11 省选挂了,即将退役……(然而apio之后得知并没有退役,感谢放我一条活路)(吐槽出题人考完才造数据,题目没有子任务之类的玩意,O(Tn^2)暴力ac了T<=100,n<=10000,这符合基本法吗)day-3-day-1 感觉期中考完挂day0 8:30的东航航班,因为"一带一路"会议,要提前三小时到机场,凌晨三点半起床,这时机场大巴都还没有的,幸好领队老师和coder107同乘一辆车,前一天说好捎了

【五】PHP数组操作函数(未完)

1.输出数组的结构:bool print_r(数组); $arr=array('jack','mike','tom'); print_r($arr);//Array ( [0] => jack [1] => mike [2] => tom ) 2.如何声明二位数组? $arr=array('name'=>array('jack','mike'),'sex'=>array('man','woman')); print_r($arr);//Array ( [name] =>