「题解」「UOJ-164」「清华集训2015」V
这道题题目简洁新颖,吸引读者阅读兴趣...
注:更完整的版本在这里。
题目
原题目
简要题目
需要你维护长度为n的序列并支持下列操作:
- 区间加法;
- 区间赋值;
- 区间每个 \(a_i\) 变成 \(\max(a_i-t,0)\);
- 单点询问值
- 单点询问历史最大值
\(n,m≤500000\),其中 \(m\) 为操作数。
正解
首先考虑,如果这道题没有历史版本我们该怎么做?
其实很简单,这里我就不赘述了 其实是我懒得说 。
那么我们考虑,对于这个 \(5\) 操作,我们应该怎么做?
首先,分析 \(3\) 操作,这是一个很特殊的操作。
对于每个 \(a_i\) ,将 \(a_i\) 修改为 \(\max(a_i-t,0)\),我们把它写成函数,即
写成一般形式,即
那么,我们可以轻松地画出这个函数的图像:
考虑能否将两个函数 \(f_1(x),f_2(x)\) 的最大值全部合并,成为 \(g(x)\),即如下图
显然是可行的,具体如何实现请自行思考,如果实在不行,看看代码也好啊。
现在,我们来看这样的函数能不能叠加,即对于 \(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\logn)\)。
#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;
}