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

题目

原题目

点这里

简要题目

需要你维护长度为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. MySQL进阶之存储引擎MyISAM与InnoDB的区别

    一.存储引擎(表类型) 通常意义上,数据库就是数据的集合,具体到计算机数据库可以是存储器上一些文件的集合或一些内存数据的集合.我们通常说的MySQL数据库.sql Server数据库等其实是数据库管理 ...

  2. 0004 工程配置settings.py

    两个目录的区别: 工程目录是指包含manage.py文件的目录 配置目录是批包含settings.py文件的目录 在配置目录中找到并打工settings.py文件,做以下配置: 01 DEBUG DE ...

  3. mac 命令行下 vim 的使用

    vi/vim 使用实例 使用 vi 来建立名为 test.txt 的文件 vi test.txt1按下 ESC 按钮回到一般模式 在一般模式中按下 :wq 储存后离开 vi 基本上 vi/vim 共分 ...

  4. (转)spring 框架介绍

    转自:http://www.cnblogs.com/wawlian/archive/2012/11/17/2775435.html 1.Spring MVC简介 Spring MVC框架是有一个MVC ...

  5. createElement(九)

    Vue.js 利用 createElement 方法创建 VNode,它定义在 src/core/vdom/create-elemenet.js 中: // wrapper function for ...

  6. Java安装及环境配置

    一.jdk安装及环境配置 1. 下载jdk 去oracle官网下载,这里使用的jdk版本为 有一个需要注意的问题就是7u71后的jdk有两个版本,奇数版本为无BUG版,偶数版包含奇数版全部内容但是有一 ...

  7. python算术

    ''' 1.对每个数进行平方, 2.求和 ''' print(sum(x ** 2 for x in range(4)))

  8. Keep-Alive 以及服务器心跳

    Keep-Alive 来源 :http://www.nowamagic.net/academy/detail/23350305 服务器心跳  来源 :http://www.cnblogs.com/lw ...

  9. Selenium(Webdriver)自动化测试常问问题

    http://blog.sina.com.cn/s/blog_c189e2590102w3bv.html Selenium(Webdriver)自动化测试常问问题 (1)selenium中如何保证操作 ...

  10. python pymysql 基本使用

    from pymysql import * # 1.创建连接数据库 conn = connect(host="localhost", port=3306, user="r ...