题目传送门

考场上感觉的确是线段树,还要维护区间最值...最值怎么维护?还要区间修改?\(update\)的时候加一下就好了吧...之后怎么搞啊?\(qwqwq\)之后好像不太会了...果断删除几乎快码完的线段树,开始写\(20\)分暴力...。感觉\(20\)直接上\(O(n^3)\)算法应该可以。注意到有\(20\)分是\(op=0\),如果数据比较热心控制在\(1e5\)内,应该可以用\(ST\)表预处理,拿到就是血赚。--以上是考场心路李辰

最后:\(0\)分,\(qwq\)。

原因:可能有负边权,那么用来更新的值(也就是代码中的\(sell\))就不能是\(0\)了,应是负无穷,因为他必须买卖一次的。但是\(ans\)应该是0.这个问题在数据结构题目中应尤为注意。

#include<cstdio>
#include<algorithm>
#include<cmath> using namespace std; int n,m,ans;
int seq[100090];
int sta[100090][30]; void subtask1()
{
for(int i=1;i<=n;i++) scanf("%d",&seq[i]);
for(int i=1;i<=m;i++)
{
int op=0,x=0,y=0,z=0;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&z);
for(int j=x;j<=y;j++) seq[j]+=z;
}
else if(op==2)
{
ans=0;
scanf("%d%d",&x,&y);
if(x<=y)
{
for(int j=x;j<=y;j++)
{
int sell=-1e9;
for(int k=j+1;k<=y;k++)
sell=max(sell,seq[k]);
ans=max(ans,sell-seq[j]);
}
printf("%d\n",ans);
}
else
{
for(int j=x;j>=y;j--)
{
int sell=-1e9;
for(int k=j-1;k>=y;k--)
sell=max(sell,seq[k]);
ans=max(ans,sell-seq[j]);
}
printf("%d\n",ans);
}
}
// for(int i=1;i<=n;i++) printf("%d ",seq[i]);
// printf("\n");
}
} int ask_max(int l,int r)
{
int k=log2(r-l+1);
return max(sta[l][k],sta[r-(1<<k)+1][k]);
} int main()
{
// freopen("wuliangye.in","r",stdin);
// freopen("wuliangye.out","w",stdout);
scanf("%d%d",&n,&m);
if(n<=500&&m<=500) {subtask1();return 0;}
for(int i=1;i<=n;i++) scanf("%d",&sta[i][0]);
for(int j=1;j<=30;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
sta[i][j]=max(sta[i][j-1],sta[i+(1<<(j-1))][j-1]);
for(int i=1;i<=m;i++)
{
int op=0,l=0,r=0;
scanf("%d",&op);
if(op==2)
{
ans=0;
scanf("%d%d",&l,&r);
if(l<=r)
{
for(int j=l;j<=r-1;j++)
ans=max(ans,ask_max(j+1,r)-sta[j][0]);
}
else
{
for(int j=l;j>=r+1;j--)
ans=max(ans,ask_max(r,j-1)-sta[j][0]);
}
printf("%d\n",ans);
}
}
return 0;
}

正解:的确是线段树,答案是需要这样维护,对于一个\(l<r\)的区间,答案是这样更新的:左区间的答案、右区间的答案、跨区间的情况。而跨区间的情况即右儿子的最大值减左儿子的最小值。普通区间维护就行了,因为有两种走法(从左到右,从右到左),那么需要记录两种答案,和区间最大值最小值。

#include<cstdio>
#include<algorithm>
#define maxn 100090 using namespace std;
typedef long long ll; int n,m;
int val[maxn];
struct Segmenttree{
int l,r;
int lazy,maxx,minn,ans1,ans2;
}t[maxn*4]; void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].maxx=t[p].minn=val[l];
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
t[p].minn=min(t[p<<1].minn,t[p<<1|1].minn);
t[p].ans1=max(max(t[p<<1].ans1,t[p<<1|1].ans1),t[p<<1|1].maxx-t[p<<1].minn);
t[p].ans2=max(max(t[p<<1].ans2,t[p<<1|1].ans2),t[p<<1].maxx-t[p<<1|1].minn);
} void update(int p)
{
if(!t[p].lazy||t[p].l==t[p].r) return ;
t[p<<1].lazy+=t[p].lazy;
t[p<<1|1].lazy+=t[p].lazy;
t[p<<1].maxx+=t[p].lazy;
t[p<<1].minn+=t[p].lazy;
t[p<<1|1].maxx+=t[p].lazy;
t[p<<1|1].minn+=t[p].lazy;
t[p].lazy=0;
} void change(int p,int l,int r,int k)
{
update(p);
if(t[p].l==l&&t[p].r==r)
{
t[p].maxx+=k;
t[p].minn+=k;
t[p].lazy+=k;
return ;
}
int mid=(t[p].l+t[p].r)>>1;
if(l>mid) change(p<<1|1,l,r,k);
else if(r<=mid) change(p<<1,l,r,k);
else change(p<<1,l,mid,k),change(p<<1|1,mid+1,r,k);
t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
t[p].minn=min(t[p<<1].minn,t[p<<1|1].minn);
t[p].ans1=max(max(t[p<<1].ans1,t[p<<1|1].ans1),t[p<<1|1].maxx-t[p<<1].minn);
t[p].ans2=max(max(t[p<<1].ans2,t[p<<1|1].ans2),t[p<<1].maxx-t[p<<1|1].minn);
} int query_MAX(int p,int l,int r)
{
update(p);
if(t[p].l==l&&t[p].r==r) return t[p].maxx;
int mid=(t[p].l+t[p].r)>>1;
if(l>mid) return query_MAX(p<<1|1,l,r);
else if(r<=mid) return query_MAX(p<<1,l,r);
else return max(query_MAX(p<<1,l,mid),query_MAX(p<<1|1,mid+1,r));
} int query_MIN(int p,int l,int r)
{
update(p);
if(t[p].l==l&&t[p].r==r) return t[p].minn;
int mid=(t[p].l+t[p].r)>>1;
if(l>mid) return query_MIN(p<<1|1,l,r);
else if(r<=mid) return query_MIN(p<<1,l,r);
else return min(query_MIN(p<<1,l,mid),query_MIN(p<<1|1,mid+1,r));
} int ask1(int p,int l,int r)
{
update(p);
if(t[p].l==l&&t[p].r==r) return t[p].ans1;
int mid=(t[p].l+t[p].r)>>1;
if(l>mid) return ask1(p<<1|1,l,r);
else if(r<=mid) return ask1(p<<1,l,r);
else return max(max(ask1(p<<1,l,mid),ask1(p<<1|1,mid+1,r)),query_MAX(p<<1|1,mid+1,r)-query_MIN(p<<1,l,mid));
} int ask2(int p,int l,int r)
{
update(p);
if(t[p].l==l&&t[p].r==r) return t[p].ans2;
int mid=(t[p].l+t[p].r)>>1;
if(l>mid) return ask2(p<<1|1,l,r);
else if(r<=mid) return ask2(p<<1,l,r);
else return max(max(ask2(p<<1,l,mid),ask2(p<<1|1,mid+1,r)),query_MAX(p<<1,l,mid)-query_MIN(p<<1|1,mid+1,r));
} int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int opt=0,l=0,r=0,w=0;
scanf("%d",&opt);
if(opt==1) scanf("%d%d%d",&l,&r,&w),change(1,l,r,w);
else if(opt==2)
{
scanf("%d%d",&l,&r);
if(l==r) printf("0\n");
else if(l<r) printf("%d\n",ask1(1,l,r));
else if(l>r) printf("%d\n",ask2(1,r,l));
}
}
return 0;
}

这题...还是比较简单的啊(!),考场上码一半放弃了...再写写应该是可以对的啊。线段树这种用左儿子+右儿子+左右儿子交界来更新答案的这种思想应该很常见了啊,还是没熟练用上。

五粮液【线段树】By cellur925的更多相关文章

  1. Luogu P1637 三元上升子序列【权值线段树】By cellur925

    题目传送门 emmm..不开结构体的线段树真香! 首先我们知道"三元上升子序列"的个数就是对于序列中的每个数,**它左边比他小的数*它右边比他大的数**.但是如何快速求出这两个数? ...

  2. Luogu P1438无聊的序列【线段树/差分】By cellur925

    题目传送门 题目大意:维护一个序列,维护区间加等差数列,单点查询的操作. 首先我们肯定是要用线段树来维护了,按照一般的思维局限,我选择了维护序列中的值,但是区间修改的时候由于公差的存在,所以区间修改有 ...

  3. Luogu P1607 庙会班车【线段树】By cellur925

    题目传送门 据说可以用贪心做?算了算了...我都不会贪.... 开始想的是用线段树,先建出一颗空树,然后输进区间操作后就维护最大值,显然开始我忽视了班车的容量以及可以有多组奶牛坐在一起的信息. 我们肯 ...

  4. 浅谈线段树 (例题:[USACO08FEB]酒店Hotel)By cellur925

    今天我们说说线段树. 我个人还是非常欣赏这种数据结构的.(逃)因为它足够优美,有递归结构,有左子树和右子树,还有二分的思想. emm这个文章打算自用,就不写那些基本的操作了... 1° 简单的懒标记( ...

  5. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  6. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  7. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  8. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  9. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

随机推荐

  1. mongodb学习之:副本集

    前面一张介绍了主从模式,现在mongoDB官方已经不建议使用主从模式了,替代方案是采用副本集的模式.副本集不能在一台电脑上操作.需要准备3台电脑进行搭建.副本集就是mongoDB副本所组成的一个集群. ...

  2. [noi2002]M号机器人

    3030年,Macsy正在火星部署一批机器人.第1秒,他把机器人1号运到了火星,机器人1号可以制造其他的机器人.第2秒,机器人1号造出了第一个机器人——机器人2号.第3秒,机器人1号造出了另一个机器人 ...

  3. 【转】hibernate懒加载的问题,failed to lazily initialize a collection of role

    hibernate懒加载的问题,failed to lazily initialize a collection of role hibernate懒加载的问题,failed to lazily in ...

  4. YUV420数据和字符信息如何利用滤镜方法进行编码?

    YUV420数据和字符信息如何利用滤镜方法进行编码?我希望用ffmpeg中的filter方法,把YUV420数据和字符信息一起编码,该怎么办呢? 本人目前只实现了把yuv420的数据进行h.264的编 ...

  5. html5--3.18 新增的output元素

    html5--3.18 新增的output元素 学习要点 了解output元素的用法 output元素:数据的输出 output元素是HTML5新增的元素,用来设置不同数据的输出 output元素的输 ...

  6. Hibernate 模糊查询 ' %?% ' SQL执行异常

    今天我在使用Hibernate 的SQL预编译之后注入参数的形式写了一条模糊查询语句.刚开始我是这么写的

  7. HihoCoder 1504 : 骑士游历 (矩阵乘法)

    描述 在8x8的国际象棋棋盘上给定一只骑士(俗称“马”)棋子的位置(R, C),小Hi想知道从(R, C)开始移动N步一共有多少种不同的走法. 输入 第一行包含三个整数,N,R和C. 对于40%的数据 ...

  8. SQL.py

    import sqlite3,sys def convert(value): if value.startswith('~'): return value.strip('~') if not valu ...

  9. yolo原理学习

    1.[yolov1]    第一步:将图像划分为S*S的栅格(grid cell),这里分成了7*7的grid cell.栅格的任务是:检测中心落在该栅格中的物体(注意,栅格中心未必与物体的中心重合, ...

  10. 使用Oracle数据库实现树形结构表的子-父级迭代(递归)查询和删除,通过级联菜单简单举例

    前言: 我们在开发中,常常遇到单表的子-父id级联的表结构,在树形的深度不确定的情况下,一次查询出某个树形结构下的所有具有子-父级关系的数据变得十分困难. 这时,我们使用oracle提供的CONNEC ...