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

题目

原题目

点这里

简要题目

需要你维护长度为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)
\]

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

考虑能否将两个函数 \(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\log⁡n)\)。

#include<cstdio>

#define rep(i,__l,__r) for(signed i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
// #define FILEOI
#define int long long
// #define int unsigned #ifdef FILEOI
# define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
# undef MAXBUFFERSIZE
# define cg (c=fgetc())
#else
# define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
} const int MAXN=5e5;
const int INF=0x3f3f3f3f3f3f3f3fll; int n,m,val[MAXN+5]; int a[(MAXN<<2)+5][2],b[(MAXN<<2)+5][2];
//a[i][0],b[i][0]:维护当前的 a,b , 若 i 不是叶节点, 那么这就是懒标记
//a[i][1],b[i][1]:维护历史最大版本 #define lc (i<<1)
#define rc (i<<1|1)
#define fff (i>>1)
#define MID ((l+r)>>1)
#define LEQ lc,l,MID
#define REQ rc,MID+1,r inline void upd(const int i){
a[i][1]=Max(a[i][1],a[i][0]+a[fff][1]);
b[i][1]=Max(b[i][1],Max(b[i][0]+a[fff][1],b[fff][1]));
a[i][0]=Max(a[i][0]+a[fff][0],-INF),b[i][0]=Max(b[i][0]+a[fff][0],b[fff][0]);
} inline void pushdown(const int i){
upd(lc),upd(rc);
a[i][0]=a[i][1]=0,b[i][0]=b[i][1]=-INF;
} void modify(const int i,const int l,const int r,const int L,const int R,const int c,const int d){
if(L<=l && r<=R){
a[i][1]=Max(a[i][1],a[i][0]+c);
b[i][1]=Max(b[i][1],Max(b[i][0]+c,d));
a[i][0]=Max(a[i][0]+c,-INF),b[i][0]=Max(b[i][0]+c,d);
return;
}
pushdown(i);
if(L<=MID)modify(LEQ,L,R,c,d);
if(MID<R)modify(REQ,L,R,c,d);
} int query(const int i,const int l,const int r,const int p,const int o){
if(l==r)return Max(val[p]+a[i][o],b[i][o]);
pushdown(i);
if(p<=MID)return query(LEQ,p,o);
else return query(REQ,p,o);
} signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
qread(n,m);
rep(i,1,n)qread(val[i]);
int t,l,r,x;
while(m--){
qread(t,l);
if(t<=3){
qread(r,x);
if(t==1)modify(1,1,n,l,r,x,-INF);
else if(t==2)modify(1,1,n,l,r,-x,0);
else modify(1,1,n,l,r,-INF,x);
}
else writc(query(1,1,n,l,t-4),'\n');
}
return 0;
}

「题解」「UOJ-164」「清华集训2015」V的更多相关文章

  1. UOJ#164:【清华集训2015】V

    浅谈区间最值操作与历史最值问题:https://www.cnblogs.com/AKMer/p/10225100.html 题目传送门:http://uoj.ac/problem/164 论文题.论文 ...

  2. 「清华集训2015」V

    「清华集训2015」V 题目大意: 你有一个序列,你需要支持区间加一个数并对 \(0\) 取 \(\max\),区间赋值,查询单点的值以及单点历史最大值. 解题思路: 观察发现,每一种修改操作都可以用 ...

  3. UOJ #164. 【清华集训2015】V | 线段树

    题目链接 UOJ #164 题解 首先,这道题有三种询问:区间加.区间减(减完对\(0\)取\(\max\)).区间修改. 可以用一种标记来表示--标记\((a, b)\)表示把原来的值加上\(a\) ...

  4. 2018.07.28 uoj#164. 【清华集训2015】V(线段树)

    传送门 线段树好题. 要求支持的操作: 1.区间变成max(xi−a,0)" role="presentation" style="position: rela ...

  5. UOJ #164 【清华集训2015】 V

    题目链接:V 这道题由于是单点询问,所以异常好写. 注意到每种修改操作都可以用一个标记\((a,b)\)表示.标记\((a,b)\)的意义就是\(x= \max\{x+a,b\}\) 同时这种标记也是 ...

  6. @uoj - 164@ 【清华集训2015】V

    目录 @description@ @solution@ @accepted code@ @details@ @description@ Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化 ...

  7. LOJ 164 【清华集训2015】V——线段树维护历史最值

    题目:http://uoj.ac/problem/164 把操作改成形如 ( a,b ) 表示加上 a 之后对 b 取 max 的意思. 每个点维护当前的 a , b ,还有历史最大的 a , b 即 ...

  8. [LOJ#2330]「清华集训 2017」榕树之心

    [LOJ#2330]「清华集训 2017」榕树之心 试题描述 深秋.冷风吹散了最后一丝夏日的暑气,也吹落了榕树脚下灌木丛的叶子.相识数年的Evan和Lyra再次回到了小时候见面的茂盛榕树之下.小溪依旧 ...

  9. [LOJ#2329]「清华集训 2017」我的生命已如风中残烛

    [LOJ#2329]「清华集训 2017」我的生命已如风中残烛 试题描述 九条可怜是一个贪玩的女孩子. 这天她在一堵墙钉了 \(n\) 个钉子,第 \(i\) 个钉子的坐标是 \((x_i,y_i)\ ...

随机推荐

  1. 一些PC小软件/工具/神器备份

    小巧.有用的工具,提升工作效率. 以下所有软件均在吾爱破解可以找到(善用搜索) everything(本机文件搜索神器) 天若OCR文字识别(强无敌) QQ拼音截屏工具(从QQ拼音/QQ中独立拿出来的 ...

  2. 5G三大应用场景

    5G三大应用场景:eMBB(增强移动宽带).eMTC(海量物联).uRLLC(高可靠低时延连接) ------20191215闪

  3. ST表求区间最值

    #include<bits/stdc++.h> #define ll long long #define lowbit(x) x&-x using namespace std; ; ...

  4. 文件上传过waf的方法

    原文链接: https://www.cesafe.com/8411.html 原始请求包: ——WebKitFormBoundary2smpsxFB3D0KbA7D Content-Dispositi ...

  5. Navicat Premium怎么设置字段的唯一性(UNIQUE)?

    参考链接:https://blog.csdn.net/Song_JiangTao/article/details/82192189 1.打开你想要设计的表 这里写图片描述2.清楚你想要设计哪个字段为唯 ...

  6. Map.getOrDefault被坑小记与optional

    错误使用样例 map.getOrDefault("account","").toString(); 在运行几小时后,发现报错空指针:查看源码如下: defaul ...

  7. Manacher算法求最长回文串模板

    #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> ...

  8. 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)

    15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经 ...

  9. 剑指offer 62. 二叉搜索树的第 k 个结点

    62. 二叉搜索树的第 k 个结点 题目描述 给定一棵二叉搜索树,请找出其中的第k小的结点.例如, (5,3,7,2,4,6,8)    中,按结点数值大小顺序第三小结点的值为4. 法一: 非递归中序 ...

  10. 题解【洛谷P1948】[USACO08JAN]电话线Telephone Lines

    题面 题解 很显然,答案满足单调性. 因此,可以使用二分答案求解. 考虑\(check\)的实现. 贪心地想,免费的\(k\)对电话线一定都要用上. 每次\(check\)时将小于\(mid\)的边权 ...