Codefoces 855F Nagini

题意

  • \(10^5\)个集合,有两种操作,一是往一个区间中的集合添加一个元素,二是询问一段区间,回答区间中每个集合最小的正数和最大的负数的绝对值之和的和,如果有一种数没出现过那么这个集合的答案就是\(0,q <= 5×10^4\)

之前没有写过吉司机线段树,这个题网上也没有\(Solution\),所以在\(CF\)上找了一个人的代码学板子,对着各种资料东拼西凑一晚上才过掉。

首先对于正数负数分开考虑,那么操作就变成了区间取\(min\)和区间求和,这个东西用吉司机线段树可以很好完成,维护区间最大值\(mx\),次大值\(smx\),最大值个数\(nmx\),区间取\(min\)标记\(tag\),设当前修改的权值是\(val\)\(mx <= val\)直接退出就好了,\(smx < val < mx\) 修改最大值就好了,\(val < smx\) 向下递归,这个东西复杂度是两个\(log\)的,可以用势能分析证明...我也不会就不证了。

对于这个题多维护一个区间是否全部有值\(allin\)\(pushup\)\(vector\)可以实现的很巧妙,就把四个值都放进去 然后排序去重,最大的就是最大值 第二个就是次大值,\(pushdown\)就把标记下放,如果更新了子区间标记的话,就把子区间的答案更新,更新的过程也很简单,看代码应该都能理解。

\(update:\)
我这种\(pushup\)的写法巨慢...不如一个个\(if\)..

    void pushup(int bh) {
        int lc = ls, rc = rs;
        allin[bh] = allin[lc] & allin[rc], sum[bh] = sum[lc] + sum[rc];
        if(mx[lc] == mx[rc]) {
            mx[bh] = mx[lc], nmx[bh] = nmx[lc] + nmx[rc];
            smx[bh] = max(smx[lc], smx[rc]);
        } else {
            if(mx[lc] < mx[rc]) swap(lc, rc);
            mx[bh] = mx[lc], nmx[bh] = nmx[lc];
            smx[bh] = max(smx[lc], mx[rc]);
        }
    }

Codes

#include<bits/stdc++.h>
#include<bits/extc++.h>

#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define For(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define FOR(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define debug(x) cout << #x << " = " << x << endl
#define mem(a, b) memset(a, b, sizeof(a))
#define cpy(a, b) memcpy(a, b, sizeof(a))
#define min(a, b) (a < b ? a : b)
#define max(a, b) (b < a ? a : b)
#define inf (0x3f3f3f3f)
#define INF (1e18)
#define pb push_back
#define mp make_pair
#define x first
#define y second

typedef unsigned long long ull;
typedef unsigned int uint;
typedef long long ll;
typedef std::pair<ll, int> PLI;
typedef std::pair<int, int> PII;
typedef long double ldb;
typedef double db;

namespace IO {
#define getc() ((S_ == T_) && (T_ = (S_ = Ch_) + fread(Ch_, 1, Buffsize, stdin), S_ == T_) ? 0 : *S_ ++)
#define putc(x) *nowps ++ = (x)
    const uint Buffsize = 1 << 15, Output = 1 << 23;
    static char Ch_[Buffsize], *S_ = Ch_, *T_ = Ch_;
    static char Out[Output], *nowps = Out;
    inline void flush(){fwrite(Out, 1, nowps - Out, stdout); nowps = Out;}
    template<class T>inline void read(T &_) {
        _ = 0; static char __; T ___ = 1;
        for(__ = getc(); !isdigit(__); __ = getc()) if(__ == '-') ___ = -1;
        for(; isdigit(__); __ = getc()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
        _ *= ___;
    }
    template<class T>inline void write(T _, char __ = '\n') {
        if(!_) putc('0');
        if(_ < 0) putc('-'), _ = -_;
        static uint sta[111], tp;
        for(tp = 0; _; _ /= 10) sta[++ tp] = _ % 10;
        for(; tp; putc(sta[tp --] ^ 48)); putc(__);
    }
    template<class T>inline bool chkmax(T &_, T __) {return _ < __ ? _ = __, 1 : 0;}
    template<class T>inline bool chkmin(T &_, T __) {return _ > __ ? _ = __, 1 : 0;}
}

using namespace std;
using namespace IO;

const int N = 1e5 + 10;
const int n = 1e5;

struct Segment_Tree {
#define ls (bh << 1)
#define rs (ls | 1)
#define mid ((l + r) >> 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r

    ll sum[N << 2]; bool allin[N << 2];
    int nmx[N << 2], mx[N << 2], smx[N << 2], tag[N << 2]; 

    void modify(int bh, int val) {
        sum[bh] -= (ll)allin[bh] * mx[bh] * nmx[bh];
        chkmin(tag[bh], val), chkmin(mx[bh], val);
        sum[bh] += (ll)mx[bh] * nmx[bh] * (allin[bh] = 1);
    }

    void pushup(int bh) {
        allin[bh] = allin[ls] & allin[rs], sum[bh] = sum[ls] + sum[rs];
        vector<int> vp = {-inf, mx[ls], smx[ls], mx[rs], smx[rs]}; 
        sort(vp.begin(), vp.end());
        vp.erase(unique(vp.begin(), vp.end()), vp.end());
        mx[bh] = vp.back(), smx[bh] = vp[vp.size() - 2];
        nmx[bh] = (mx[bh] == mx[ls]) * nmx[ls] + (mx[bh] == mx[rs]) * nmx[rs];
    }

    void pushdown(int bh) {
        if(tag[bh] ^ inf) modify(ls, tag[bh]), modify(rs, tag[bh]), tag[bh] = inf;
    }

    void build(int bh, int l, int r) {
        tag[bh] = mx[bh] = inf, smx[bh] = -inf;
        nmx[bh] = r - l + 1, sum[bh] = allin[bh] = 0;
        if(l ^ r) build(lson), build(rson);
    }

    void update(int bh, int l, int r, int x, int y, int z) {
        if(y < l || x > r || mx[bh] <= z) return;
        if(x <= l && r <= y && smx[bh] <= z) modify(bh, z);
        else {
            pushdown(bh);
            update(lson, x, y, z);
            update(rson, x, y, z);
            pushup(bh);
        }
    }

}T[2];

ll query(int bh, int l, int r, int x, int y) {
    if(y < l || x > r || !T[0].sum[bh] || !T[1].sum[bh]) return 0;
    if(x <= l && r <= y && T[0].allin[bh] && T[1].allin[bh]) 
        return T[0].sum[bh] + T[1].sum[bh];
    T[0].pushdown(bh), T[1].pushdown(bh);
    return query(lson, x, y) + query(rson, x, y);
}

int main() {
#ifdef ylsakioi
    file("cf885f");
#endif
    int q, opt, x, y, z;

    T[0].build(1, 1, n), T[1].build(1, 1, n);

    for(read(q); q -- ; ) {
        read(opt), read(x), read(y); -- y;
        if(opt == 1) read(z), T[z > 0].update(1, 1, n, x, y, abs(z));
        else write(query(1, 1, n, x, y));
    }

    return flush(), 0;
}

猜你喜欢

转载自www.cnblogs.com/brunch/p/10098411.html