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

题目

原题目

点这里

简要题目

需要你维护长度为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. Chrome浏览器控制台报Refused to get unsafe header "XXX"的错误

    最近在调试后端下载的接口时在浏览器的控制台中发现了红色的错误信息,例如Refused to get unsafe header "XXX":前端是采用XMLHttpRequest对 ...

  2. easyui-numberbox后台获取数据后,鼠标一点击就自动清空了

    <input type="text" name="txtMeterInitData" id="txtMeterInitData" cl ...

  3. 2018ICPC南京站Problem G. Pyramid

    题意: 找有多少个等边三角形 解析: 首先打标找规律,然后对式子求差分 0,1,5,15,35,70,126,210... 1,4,10,20,35,56... 3,6,10,15,21... 3,4 ...

  4. 2.Ubuntu安装 Docker

    平台支持 Docker CE 支持多种平台,如下表所示 桌面 平台 架构 Docker Desktop for Mac (macOS) X64 Docker Desktop for Windows ( ...

  5. windows 服务启动外部程序

    服务使用Process启动外部程序没窗体 在WinXP和Win2003环境中,安装服务后,右键单击服务“属性”-“登录”选项卡-选择“本地系统帐户”并勾选“允许服务与桌面交互”即可. 在Win7及以后 ...

  6. JFinalSwagger插件

    个人博客 地址:http://www.wenhaofan.com/article/20190304101839 jfinal使用swagger的极简插件 码云地址:https://gitee.com/ ...

  7. AE创建组件失败,项目中已存在对esri.arcgis.***的引用

    AE创建组件失败,项目中已存在对esri.arcgis.***的引用 解决办法:在解决方案资源管理器的引用中把错误提示中的引用删掉,再创建组件就没问题了.

  8. python面试的100题(12)

    25.求出列表所有奇数并构造新列表 a=[1,2,3,4,5,6,7,8,9,10] res=[i for i in a if i%2==1] print(res) 结果为:[1, 3, 5, 7, ...

  9. WMITools修复wmi劫持--hao643.com/jtsh123劫持(修改快捷方式跳转至hao123.com)

    >症状:所有浏览器快捷方式,都被加上尾巴,例如IE的:"C:\Program Files\Internet Explorer\iexplore.exe" http://hao ...

  10. Java 散列集笔记

    散列表 散列表(hash table)为每个对象计算一个整数,称为散列码(hash code). 若需要自定义类,就要负责实现这个类的hashCode方法.注意自己实现的hashCode方法应该与eq ...