「题解」「UOJ-164」「清华集训2015」V

这道题题目简洁新颖,吸引读者阅读兴趣...

注:更完整的版本在这里

题目

原题目

点这里

简要题目

需要你维护长度为n的序列并支持下列操作:

  1. 区间加法;
  2. 区间赋值;
  3. 区间每个 \(a_i\) 变成 \(\max⁡(a_i-t,0)\)
  4. 单点询问值
  5. 单点询问历史最大值

\(n,m≤500000\),其中 \(m\) 为操作数。

正解

首先考虑,如果这道题没有历史版本我们该怎么做?

其实很简单,这里我就不赘述了 其实是我懒得说

那么我们考虑,对于这个 \(5\) 操作,我们应该怎么做?

首先,分析 \(3\) 操作,这是一个很特殊的操作。

对于每个 \(a_i\) ,将 \(a_i\) 修改为 \(\max(a_i-t,0)\),我们把它写成函数,即

\[f(x)=\max(x-t,0) \]

写成一般形式,即

\[f(x)=\max(x+a,b) \]

那么,我们可以轻松地画出这个函数的图像:

image

考虑能否将两个函数 \(f_1(x),f_2(x)\) 的最大值全部合并,成为 \(g(x)\),即如下图

image

显然是可行的,具体如何实现请自行思考,如果实在不行,看看代码也好啊。

现在,我们来看这样的函数能不能叠加,即对于 \(f(x)=\max(x+a,b)\),能不能给 \(a+\Delta\) 或者 \(b+\Delta\)

显然这也是可行的,即新的 \(f'(x)=\max(x+a+\Delta,b)\) 或者是 \(f'(x)=\max(x+a,b+\Delta)\)

发现这个函数有叠加性以及能够维护函数最大,发现似乎可以用这样的函数来做这道题,但是,需要对我们的操作进行一些变换:

设标记 \((a,b)\) 表示将 \(x\) 变成 \(\max⁡(a+x,b)\)

  • 区间加上 \(a\)\((a,-\infty)\)

  • 区间赋值为 \(a\)\((-\infty,a)\)

  • 区间每个 \(x\) 变成 \(\max⁡(x-a,0):(-a,0)\)

  • 合并 \((a,b)\)\((c,d)\)\((a+c,\max⁡(b+c,d))\)

假设对一个位置作用的标记对应函数依次为 \(f_1 (x),f_2 (x)\ldots,f_k (x)\)

历史最大值对应函数为 \(\max\{x,f_1 (x),f_2(f_1(x)),……,f_k (f_{k-1}(……f_1(x)))\}\)

如若能维护出该函数,历史最大值即可维护出。

可以发现将两个这样函数取 \(\max\) 后仍然是一个形式一样的函数(见上面的图)。于是历史最大值的函数即可维护。用线段树在每个区间维护当前标记的函数和历史最大值的函数即可,这两个都支持 \(\mathcal O(1)\) 合并。于是复杂度为 \(\mathcal O(n\log⁡n)\)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cstring>
using namespace std;

// #define NDEBUG
#include <cassert>

namespace Elaina{
    #define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
    #define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
    #define fi first
    #define se second
    #define mp(a, b) make_pair(a, b)
    #define Endl putchar('\n')
    #define mmset(a, b) memset(a, b, sizeof a)
    #define mmcpy(a, b) memcpy(a, b, sizeof a)
    // #define int long long
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    template<class T>inline T fab(T x){ return x<0? -x: x; }
    template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
    template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
    template<class T>inline T readin(T x){
        x=0; int f=0; char c;
        while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
        for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
        return f? -x: x;
    }
    template<class T>inline void writc(T x, char s='\n'){
        static int fwri_sta[1005], fwri_ed=0;
        if(x<0) putchar('-'), x=-x;
        do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
        while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
        putchar(s);
    }
}
using namespace Elaina;

const int maxn=5e5;
const ll inf=1ll<<50;

ll x[maxn+5];
int n, m;

namespace saya{
    struct Func{
        ll a, b;
        inline Func operator +(const Func& rhs) const{
            return Func{max(a, rhs.a), max(b, rhs.b)};
        }
        inline Func operator ^(const Func& rhs) const{
            return Func{max(a+rhs.a, -inf), max(a+rhs.b, b)};
        }
        inline ll operator ()(const ll& x) const{ return max(x+a, b); }
    };
    Func tag[maxn<<2|2], histag[maxn<<2|2];
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define mid ((l+r)>>1)
    #define fa (i>>1)
    #define _lhs ls, l, mid
    #define _rhs rs, mid+1, r
    #define _this i, l, r
    inline void update(int i){
        histag[i]=histag[i]+(histag[fa]^tag[i]);
        tag[i]=tag[fa]^tag[i];
    }
    inline void pushdown(int i){
        update(ls), update(rs), tag[i]=histag[i]=Func{0, -inf};
    }
    void build(int i, int l, int r){
        tag[i]=histag[i]=Func{0, -inf};
        if(l==r) return;
        build(_lhs), build(_rhs);
    }
    void modify(int L, int R, Func f, int i, int l, int r){
        if(L<=l && r<=R){
            histag[i]=histag[i]+(f^tag[i]);
            tag[i]=f^tag[i];
            return;
        }
        pushdown(i);
        if(L<=mid) modify(L, R, f, _lhs);
        if(mid<R) modify(L, R, f, _rhs);
    }
    ll query(int p, int type, int i, int l, int r){
        if(l==r) return type? histag[i](x[p]): tag[i](x[p]);
        pushdown(i);
        if(p<=mid) return query(p, type, _lhs);
        else return query(p, type, _rhs);
    }
    #undef ls
    #undef rs
    #undef mid
    #undef fa
    #undef _lhs
    #undef _rhs
    #undef _this
}

signed main(){
    n=readin(1), m=readin(1);
    rep(i, 1, n) x[i]=readin(1);
    saya::build(1, 1, n);
    int op, l, r, x, y;
    while(m--){
        op=readin(1);
        if(op==1){
            l=readin(1), r=readin(1), x=readin(1);
            saya::modify(l, r, {x, -inf}, 1, 1, n);
        }
        else if(op==2){
            l=readin(1), r=readin(1), x=readin(1);
            saya::modify(l, r, {-x, 0}, 1, 1, n);
        }
        else if(op==3){
            l=readin(1), r=readin(1), x=readin(1);
            saya::modify(l, r, {-inf, x}, 1, 1, n);
        }
        else{
            y=readin(1);
            writc(saya::query(y, op-4, 1, 1, n));
        }
    }
    return 0;
}
posted @ 2020-01-19 21:29  Arextre  阅读(305)  评论(0编辑  收藏  举报