【2019.10.7 CCF-CSP-2019模拟赛 T2】绝对值(abs)(线段树细节题)
找规律
设\(p_i=a_{i+1}-a_i\),则答案就是\(\sum_{i=1}^{n-1}p_i\)。
考虑若将\(a_i\)加上\(x\)(边界情况特殊考虑),就相当于是将\(p_{i-1}\)加\(x\),\(p_i\)减\(x\)。
先考虑\(p_{i-1}\)加\(x\)所造成的影响:
- 当\(p_{i-1}\ge0\)时,就相当于将答案加上\(x\)。
- 当\(-x\le p_{i-1}<0\)时,原先的答案是\(-p_{i-1}\),新的答案是\(x+p_{i-1}\),所以答案加上\(x+2p_{i-1}\)。
- 当\(p_{i-1}<-x\)时,就相当于将答案减去\(x\)。
- 不难发现,由于\(-x=x-2x\),所以第二、三两种情况可以概括为:当\(p_{i-1}<0\)时,答案加上\(x+2max\{p_{i-1},-x\}\)。
同理,\(p_i\)减\(x\)所造成的影响就是:
- 当\(p_i\le0\)时,答案加上\(x\)。
- 当\(p_i>0\)时,答案加上\(x+max\{-2p_i,-x\}\)。
显然,若存在\(p_{i-1}\ge0\)且\(p_i\le0\),肯定是最优的。
否则,\(p_i\)就是一段小于等于\(0\)的数和一段大于等于\(0\)的数。
在左边这一段中选择的贡献,就是\(x+2p_{i-1}+x=2x+2p_{i-1}\),只要求出\(p_{i-1}\)的最大值即可。
同理,在右边这一段中选择的贡献就是\(2x-2p_i\),只要求出\(-p_i\)的最大值即可。
而在中间选择的贡献可以直接暴力算,就是新的绝对值之和减去旧的绝对值之和。
以上即为大致思路,下面是具体实现中的一些细节。
具体细节
\(Q\):如何处理区间修改?
\(A\):区间修改时可发现中间部分的\(p\)不变,只有两端发生变化,很好处理。
\(Q\):如何判断是否存在\(p_{i-1}\ge0\)且\(p_i\le0\)?
\(A\):可以开一棵线段树,每一位存储这一位上是否满足\(p_{i-1}\ge0\)且\(p_i\le0\),然后区间查询即可。
\(Q\):如何求\(p_{i-1}\)和\(-p_i\)的最大值?
\(A\):另开两棵线段树,分别存储\(p_i\)和\(-p_i\)。
\(Q\):如何求出\(p_i\)中小于等于\(0\)的部分与大于等于\(0\)的部分的分界点?
\(A\):线段树上二分即可。
当然,还有边界情况等一些特殊情况,需要大力讨论,注意细节!
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define max(x,y) ((x)>(y)?(x):(y))
#define Gmax(x,y) (x<(y)&&(x=(y)))
#define abs(x) ((x)<0?-(x):(x))
#define LL long long
#define INF 1e18
using namespace std;
int n;LL a[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class SegmentTreeSolver
{
private:
LL p[N+5];
class SegmentTree//线段树三合一,毕竟都是单点修改+区间求最大值
{
private:
#define PT CI l=1,CI r=n,CI rt=1
#define LT x,y,l,mid,rt<<1
#define RT x,y,mid+1,r,rt<<1|1
#define PU(x) (V[x]=max(V[x<<1],V[x<<1|1]))
LL V[N<<2];
public:
I void Upt(CI x,Con LL& y,PT)//单点修改
{
if(l==r) return (void)(V[rt]=y);RI mid=l+r>>1;
x<=mid?Upt(LT):Upt(RT),PU(rt);
}
I LL Qry(CI x,CI y,PT)//区间求最大值
{
if(x<=l&&r<=y) return V[rt];RI mid=l+r>>1;LL g,t=-INF;
return x<=mid&&(g=Qry(LT),Gmax(t,g)),y>mid&&(g=Qry(RT),Gmax(t,g)),t;
}
I int Find(CI x,CI y,PT)//线段树上二分,求出两部分的分界点
{
if(l==r) return V[rt]>=0?l:0;RI mid=l+r>>1,t;
if(x<=l&&r<=y) return V[rt<<1|1]>=0?Find(RT):Find(LT);
if(y>mid&&(t=Find(RT))) return t;return Find(LT);
}
}S1,S2,T;
public:
I void Solve()
{
RI Qt,op,l,r,x,g;LL f,k,t=0;
for(RI i=1;i^n;++i) p[i]=a[i+1]-a[i],t+=abs(p[i]),S1.Upt(i,p[i]),S2.Upt(i,-p[i]);//初始化
for(RI i=1;i<=n-2;++i) p[i]>=0&&p[i+1]<=0&&(T.Upt(i,1),0);//初始化
F.read(Qt);W(Qt--) switch(F.read(op,l,r,x),op)//读入操作
{
case 1:
k=-2*x,l==1&&(Gmax(k,abs(p[1]-x)-abs(p[1])),++l),//特殊处理边界,避免讨论
r==n&&(Gmax(k,abs(p[n-1]+x)-abs(p[n-1])),--r);//特殊处理边界,避免讨论
if(l>r) goto Print;if(T.Qry(l-1,r-1)) {Gmax(k,2*x);goto Print;}//如果存在p[i-1]>=0且p[i]<=0的情况
if(p[l-1]<=0&&p[r]<=0) {f=S1.Qry(l-1,r-1),Gmax(f,-x),Gmax(k,2*f+2*x);goto Print;}//如果全部小于等于0
if(p[l-1]>=0&&p[r]>=0) {f=S2.Qry(l,r),Gmax(f,-x),Gmax(k,2*f+2*x);goto Print;}//如果全部大于等于0
g=S2.Find(l-1,r),Gmax(k,abs(p[g]+x)+abs(p[g+1]-x)-abs(p[g])-abs(p[g+1])),//处理在中间选择的贡献
g>l-1&&(f=S1.Qry(l-1,g-1),Gmax(f,-x),Gmax(k,2*f+2*x)),//处理在左边这一段中选择的贡献
g+1<r&&(f=S2.Qry(g+2,r),Gmax(f,-x),Gmax(k,2*f+2*x));//处理在右边这一段中选择的贡献
Print:F.writeln(t+k);break;//输出答案
case 2:
l^1&&(t-=abs(p[l-1]),p[l-1]+=x,t+=abs(p[l-1]),S1.Upt(l-1,p[l-1]),S2.Upt(l-1,-p[l-1]),0),//处理左边
r^n&&(t-=abs(p[r]),p[r]-=x,t+=abs(p[r]),S1.Upt(r,p[r]),S2.Upt(r,-p[r]),0),//处理右边
l^1&&//再处理左边
(
l^n&&(T.Upt(l-1,0),p[l-1]>=0&&p[l]<=0&&(T.Upt(l-1,1),0)),
l^2&&(T.Upt(l-2,0),p[l-2]>=0&&p[l-1]<=0&&(T.Upt(l-2,1),0))
),
r^n&&//再处理右边
(
r^(n-1)&&(T.Upt(r,0),p[r]>=0&&p[r+1]<=0&&(T.Upt(r,1),0)),
r^1&&(T.Upt(r-1,0),p[r-1]>=0&&p[r]<=0&&(T.Upt(r-1,1),0))
);break;//注意这里之所以要分开处理,是因为另一边对p的修改可能影响到这一边的判断
}
}
}S;
int main()
{
freopen("abs.in","r",stdin),freopen("abs.out","w",stdout);
RI i;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);return S.Solve(),F.clear(),0;
}
【2019.10.7 CCF-CSP-2019模拟赛 T2】绝对值(abs)(线段树细节题)的更多相关文章
- 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径
LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...
- 【2019.7.15 NOIP模拟赛 T2】与非树(nand)(树形DP)
树形\(DP\) 实际上,这道题应该不是很难. 我们设\(f_{x,i,j}\)表示在以\(x\)为根的子树内,原本应输出\(i\),结果输出了\(j\)的情况数. 转移时,为了方便,我们先考虑与,再 ...
- 2018-8-10 模拟赛T3(可持久化线段树)
出题人说:正解离线按DFS序排序线段维护区间和 但是对于树上每个点都有一个区间和一个值,两个点之间求1~m的区间和,这不就是用可持久化线段树吗. 只不过这个线段树需要区间修改,不过不需要标记下传,询问 ...
- 5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
LINK:波波老师 LINK:同bzoj 1396 识别子串 不过前者要求线性做法 后者可以log过.实际上前者也被我一个log给水过了. 其实不算很水 我自认跑的很快罢了. 都是求经过一个位置的最短 ...
- 模拟赛T2 交换 解题报告
模拟赛T2 交换 解题报告 题目大意: 给定一个序列和若干个区间,每次从区间中选择两个数修改使字典序最小. \(n,m\) 同阶 \(10^6\) 2.1 算法 1 按照题意模拟,枚举交换位置并比较. ...
- 2018.10.05 TOPOI提高组模拟赛 解题报告
得分: \(100+5+100=205\)(真的是出乎意料) \(T1\):抵制克苏恩(点此看题面) 原题: [BZOJ4832][Lydsy1704月赛] 抵制克苏恩 应该还是一个比较简单的\(DP ...
- 20161003 NOIP 模拟赛 T2 解题报告
Weed duyege的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹. 为了查出真相,duyege 准备修好电脑之后再进行一次金坷垃的模拟实验. 电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为 ...
- @省选模拟赛03/16 - T3@ 超级树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...
- [模拟赛] T2 不等数列
Description 将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入">"和"<".问在所有排列中,有多少个排列恰好有k个&qu ...
随机推荐
- jsf中的按钮加弹框的两种形式
第一种: <p:commandButton value="一键移除" action="#{ProjectPackageManageBackingBean.remov ...
- Xcode真机运行报错iPhone has denied the launch request
1.打开钥匙串 ->Apple Worldwide Developer Relations Certification Authority ->双击 并点击信任->选择使用系统默认2 ...
- Bug 29041775 : ORA-41401: Define character set () does not match database character set ()
oracle版本12.2.0.1 Errors in file /u01/app/oracle/diag/rdbms/sibcyb1/CYB111/trace/CYB111_q003_166752.t ...
- Centos7 下添加开机自启动服务和脚本
1.添加开机自启服务 #设置jenkins服务为自启动服务 systemctl enable jenkins.service #启动jenkins服务 systemctl start jenkins. ...
- 表单生成器(Form Builder)之伪造表单数据mongodb篇
这篇文章终于回到了正轨:为mongodb伪造数据.之前的随机数.随机车牌照.随机时间还有这篇笔记中的获取指定长度的中文字符串,都是为这篇笔记做准备.看一下我们的准备(基础代码) // 1.获取指定范围 ...
- Objective-C中 #include 和 #import 的区别
由于 Objective-C 兼容 C 语言,所以导入文件时, 可以使用 #include,也可以使用 #import (Objective-C 新增的) 如: #include <stdio. ...
- R学习
R内容: R-1 基础 R-2 基础绘图 R-3 t分布--t置信区间--t检验 R-4 方差分析 R-5 相关分析-卡方分析 R-6 线性回归模型分析流程 R实战第7章 线性回归 逻辑回归 主成分分 ...
- RTP Payload Format for H264 Video
基础传输结构 rtp中对于h264数据的存储分为两层,分别是 VCL: video coding layer 视频编码层 这是h264中block, macro block 以及 slice级别的定义 ...
- xamarin调试android部署到模拟器错误记录:Deployment failed Mono.AndroidTools.InstallFailedException: Unexpected install output: Error: Could not access the Package Manager. Is the system running?
问题记录: 1.生成 ok. 2.昨天也是能部署到模拟器的. 但是今天部署的时候就报了这样的一个错误 Deployment failed Mono.AndroidTools.InstallFailed ...
- 被忽略的CSS规则
说起CSS规则,除了普通规则(属性和值,key:value),可能大家都会想到@media,@keyframes,@fontface等常用的,那剩余的大家是否有所了解呢. 我们先来看一看CSS有哪些规 ...