题目传送门

考场上感觉的确是线段树,还要维护区间最值...最值怎么维护?还要区间修改?\(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. 原来浏览器原生支持JS Base64编码解码 outside of the Latin1 range

    原来浏览器原生支持JS Base64编码解码 « 张鑫旭-鑫空间-鑫生活 https://www.zhangxinxu.com/wordpress/2018/08/js-base64-atob-bto ...

  2. 20170313 ABAP以jason 格式返回值到http(接口内容返回)

     问题1: 返回jason 格式信息给你们这步不通, 这个可以怎么处理, ***得到SCP 系统开发回复,他们需要调整方法: (1)调用函数做RETURN, IT_ZSMLSCPNOTICE-FUNC ...

  3. 【Effective C++】实现

    条款26:尽可能延后变量定义式的出现时间 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本. 所以我们应该在定义对象时,尽可能 ...

  4. STM32 ~ JTAG、SWD和串口下载的问题

    最近有一个项目用到STM32,为了使PCB布线方便一些所以改了一些引脚,占用了JTAG接口的PA15和PB3,所以要禁用一下JTAG,下载采用SWD模式.这样在实际操作中做出一些总结(方法网上都有.这 ...

  5. Ubuntu环境下配置Android Studio【转】

    本文转载自:https://www.jianshu.com/p/1f6295f9c955 之前学习Android开发的时候,一直跟各种教程一样,使用的是Eclipse+ADT,主要是比较方便,容易上手 ...

  6. jquery特效(6)—判断复选框是否选中进行答题提示

    前面有一段时间思想开了小差,跟着师父学习了一段时间才发现差距很大,看来我要奋起直追~\(≧▽≦)/~啦啦啦. 最近公司在做一个项目,需要根据用户选择的选项给出相应的提示,下面来看我写的测试程序的效果: ...

  7. Hihocoder #1121 二分图一•二分图判定( bfs或者dfs搜索实现 搜索的过程中进行 节点标记 *【模板】)

    对于拿到的相亲情况表,我们不妨将其转化成一个图.将每一个人作为一个点(编号1..N),若两个人之间有一场相亲,则在对应的点之间连接一条无向边.(如下图) 因为相亲总是在男女之间进行的,所以每一条边的两 ...

  8. spring类扫描注入-----类扫描的注解解析器

    通过类扫描注入到容器中,这种方式,在实际开发中还是很常用的,可以看下自己的配置文件,就会发现,自己公司的项目,搞不好就是这么注入的. 起码,我发现我公司的项目就是这么干的. 下面来演示一下简单的例子: ...

  9. Redis雪崩效应以及解决方案

    缓存雪崩产生的原因 缓存雪崩通俗简单的理解就是:由于原有缓存失效(或者数据未加载到缓存中),新缓存未到期间(缓存正常从Redis中获取,如下图)所有原本应该访问缓存的请求都去查询数据库了,而对数据库C ...

  10. LDAP解释(转)

    我要着重指出,LDAP是一个数据库,但是又不是一个数据库.说他是数据库,因为他是一个数据存储的东西.但是说他不是数据库,是因为他的作用没有数据库这么强大,而是一个目录. 为了理解,给一个例子就是电话簿 ...