Description

属于小Q管辖的n座摩天楼从左往右排成一排,编号依次为1到n,第i座摩天楼的高度为h_i。小Q会进行m次以下两种 操作之一: 1 l
r,询问h_l+h_{l+1}+…+h_r。 2 l
r,对于第l到r的每座摩天楼i,如果上次操作结束时h_i<h_{i-1},则将第i座摩天楼再往上造一层,即h_i增加1。
你可以认为h_0=正无穷。 请写一个程序回答小Q的每个询问。注意,此题操作一和操作二弄反了

Input

第一行包含两个正整数n,m(1<=n<=100000,1<=m<=min(100000,2n)),分别表示摩天楼的数量以及操作的数量。
第二行包含n个正整数h_1,h_2,…,h_n(1<=h_i<=n),表示每座楼的高度。
接下来m行,每行三个正整数op,l,r(1<=op<=2,1<=l<=r<=n),分别表示每个操作。
因为小Q觉得错乱不齐的建筑更加美观,因此你可以认为数据是完全随机的。

Output

对于每个询问输出一行一个整数,即区间内所有摩天楼的高度之和。

Sample Input

5 8

1 3 2 2 4

1 2 4

2 2 2

2 3 3

2 4 4

1 1 3

2 1 1

2 2 2

2 3 3

Sample Output

3

3

2

2

3

3

题解

观察到这个h是随机的
于是可以大胆猜想一种关于差值的算法
一开始觉得可以分块,每个块维护块内和前面差值最小的,加就直接加然后差值变为0了就得暴力重构
然而分块这样会出现一些问题,大概是差值变为0了之后每个块的重构次数就会暴涨
然后这样就不能分析了
而且感觉代码也超级难写的样子,还要讨论块前一个的贡献
可以把分块改成线段树,同样维护区间差值最小
单考虑一个点的话,有两种东西要维护
如果他比左边的点要矮,你需要维护一个值使得加了这个值的次数后这个点就不增了
如果他比右边的点要矮,同样要维护一个值使得加了这个值的次数后右边的点就要变得增了
注意这里记录的值都是在处于左边/右边的点不动的情况下讨论的,因为动的话差值并不会缩小
于是可以直接维护了,加就直接加
每次找到差值为0的地方,把这个点拿出来暴力重构他,以及他左边的点的差值和右边点的差值
注意并不能重构左右的点,因为重构左右的点的话可能会使得左右的点下一次就不能被增加了,但是实际上是可以被增加的,因为左右的左右的点还没有把标记下传
具体的话…可以看看代码
有注释感觉挺好懂的

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{int f=1,x=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
int stack[20];
inline void write(LL x)
{if(x<0){putchar('-');x=-x;}if(!x){putchar('0');return;}int top=0;while(x)stack[++top]=x%10,x/=10;while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=100005;int a[MAXN],n,m;
int ok[MAXN],L[MAXN],R[MAXN];//这个点是否可以增加   左边是否要注意重构   右边是否要注意重构
bool f1(int x){return a[x-1]>a[x];}//这个点是否可以增加
int cl(int x){return (ok[x]&&!ok[x-1])?a[x-1]-a[x]:999999999;}
int cr(int x){return (ok[x]&&!ok[x+1])?a[x+1]-a[x]:999999999;}int list[MAXN],tp;//需要重构的点 struct segtree
{LL sum[4*MAXN];int size[4*MAXN],add[4*MAXN],minl[4*MAXN],minr[4*MAXN];//有多少个可用点 void pushup(int now){size[now]=size[lc]+size[rc];sum[now]=sum[lc]+sum[rc];minl[now]=min(minl[lc],minl[rc]);minr[now]=min(minr[lc],minr[rc]);}void pushdown(int now){if(!add[now])return ;sum[lc]+=add[now]*size[lc];sum[rc]+=add[now]*size[rc];add[lc]+=add[now];add[rc]+=add[now];minl[lc]-=add[now];minl[rc]-=add[now];minr[lc]-=add[now];minr[rc]-=add[now];add[now]=0;}void buildtree(int now,int l,int r){if(l==r){size[now]=ok[l];sum[now]=a[l];minl[now]=L[l];minr[now]=R[l];return ;}int mid=(l+r)/2;buildtree(lc,l,mid);buildtree(rc,mid+1,r);pushup(now);}LL qry(int now,int l,int r,int ql,int qr){if(l==ql&&r==qr)return sum[now];int mid=(l+r)/2;pushdown(now);if(qr<=mid)return qry(lc,l,mid,ql,qr);else if(mid+1<=ql)return qry(rc,mid+1,r,ql,qr);else return qry(lc,l,mid,ql,mid)+qry(rc,mid+1,r,mid+1,qr);}void newcal(int now,int l,int r,int p)//得到a[p]新的值{if(l==r){if(ok[l])a[l]+=add[now];add[now]=0;return ;}int mid=(l+r)/2;pushdown(now);if(p<=mid)newcal(lc,l,mid,p);else newcal(rc,mid+1,r,p);}void modify(int now,int l,int r,int ql,int qr){if(l==ql&&r==qr){sum[now]+=size[now];add[now]++;minl[now]--;minr[now]--;return ;}int mid=(l+r)/2;pushdown(now);if(qr<=mid)modify(lc,l,mid,ql,qr);else if(mid+1<=ql)modify(rc,mid+1,r,ql,qr);else modify(lc,l,mid,ql,mid),modify(rc,mid+1,r,mid+1,qr);pushup(now);}void work(int now,int l,int r,int p)//把p的线段树节点全部更换 {if(l==r){sum[now]=a[l];size[now]=ok[l];minl[now]=L[l];minr[now]=R[l];return ;}int mid=(l+r)/2;pushdown(now);if(p<=mid)work(lc,l,mid,p);else work(rc,mid+1,r,p);pushup(now);}void putl(int now,int l,int r,int p,int c){if(l==r){minl[now]=c;return ;}int mid=(l+r)/2;pushdown(now);if(p<=mid)putl(lc,l,mid,p,c);else putl(rc,mid+1,r,p,c);minl[now]=min(minl[lc],minl[rc]);}void putr(int now,int l,int r,int p,int c){if(l==r){minr[now]=c;return ;}int mid=(l+r)/2;pushdown(now);if(p<=mid)putr(lc,l,mid,p,c);else putr(rc,mid+1,r,p,c);minr[now]=min(minr[lc],minr[rc]);}void fix(int now,int l,int r){if(minl[now]>0&&minr[now]>=0)return ;if(l==r){if(minl[now]<=0&&list[tp]!=l)list[++tp]=l;//这个点的左边贡献需要被更改了if(minr[now]<0)list[++tp]=l+1;//右边的点左边贡献需要被更改了return ; }int mid=(l+r)/2;pushdown(now);fix(lc,l,mid);fix(rc,mid+1,r);}
}seg;void do1(int x){if(x>=1&&x<=n)seg.newcal(1,1,n,x);}
void do2(int x){if(x>=1&&x<=n)seg.work(1,1,n,x);}
void do3(int x){if(x>=1&&x<=n)seg.putl(1,1,n,x,cl(x));}
void do4(int x){if(x>=1&&x<=n)seg.putr(1,1,n,x,cr(x));}void go(int x)
{if(x<1||x>n)return ;do1(x);do1(x-1);do1(x+1);ok[x]=f1(x);L[x]=cl(x);R[x]=cr(x);do2(x);do3(x+1);do4(x-1);
}int main()
{n=read();m=read();a[0]=999999999;for(int i=1;i<=n;i++)a[i]=read(),ok[i]=f1(i);ok[n+1]=1;for(int i=1;i<=n;i++)L[i]=cl(i),R[i]=cr(i);seg.buildtree(1,1,n);while(m--){int opt=read(),u=read(),v=read();if(opt==2)pr2(seg.qry(1,1,n,u,v));else{seg.modify(1,1,n,u,v);tp=0;seg.fix(1,1,n);for(int i=1;i<=tp;i++)go(list[i]);go(u);go(v+1);}}return 0;
}

[bzoj5050][线段树]建造摩天楼相关推荐

  1. POJ Mayor's posters——线段树+离散化

    原文:http://blog.163.com/cuiqiongjie@126/blog/static/85642734201261151553308/ 大致题意: 有一面墙,被等分为1QW份,一份的宽 ...

  2. BZOJ2957:楼房重建(线段树)

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

  3. 【BZOJ3073】[Pa2011]Journeys 线段树+堆优化Dijkstra

    [BZOJ3073][Pa2011]Journeys Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在 ...

  4. l2-004 这是二叉搜索树吗? (25分)_什么是 “线段树” ?

    线段树是一个复杂的数据结构,比较难理解,也比较难解释清楚.在我将这个数据结构反复学习了五遍的时候,我终于有了信心写出这篇介绍线段树的文章.希望大家能够掌握这种数据结构. 这篇文章比较长,建议大家耐心阅 ...

  5. 【BZOJ3387】[Usaco2004 Dec]Fence Obstacle Course栅栏行动 线段树

    [BZOJ3387][Usaco2004 Dec]Fence Obstacle Course栅栏行动 Description 约翰建造了N(1≤N≤50000)个栅栏来与牛同乐.第i个栅栏的z坐标为[ ...

  6. [BZOJ 2957]楼房重建(线段树)

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

  7. 主席树——多棵线段树的集合

    主席树: (不要管名字) 我们有的时候,会遇到很多种情况,对于每一种情况,都需要通过线段树的操作实现. 碰巧的是,相邻两种情况下的线段树的差异不大.(总体的差异次数是O(N)级别的,均摊就是O(常数) ...

  8. bzoj2957 奥妙重重的线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树的query和update竟然还可以结合起来用! 题意:小A的楼房外有一大片施工工地, ...

  9. [帝皇杯day 1] [NOIP2018模拟赛]小P的loI(暴力+素筛),【NOIP模拟赛】创世纪(贪心),无聊的数对(线段树)

    文章目录 T1:小P的lol title solution code T2:创世纪 title solution code T3:无聊的数对 title solution code T1:小P的lol ...

最新文章

  1. Python打印json文件,实现输出
  2. 吐槽一下现在的代码编辑器
  3. 96. (GO)不同的二叉搜索树
  4. python typing typescript_将 python 数据转化为 TypeScript 格式
  5. python神器pandas_Python数据处理神器,pandas入门必需理解的核心内容
  6. 计算机桌面老是弹出广告,桌面老是弹出广告怎么办? 爱问知识人
  7. vulfocus靶场安装教程
  8. 用java设计秒表_运用Java编写 秒表程序
  9. zbb20180913 java synchronized同步静态方法和同步非静态方法的异同
  10. 通过实验来理解代理ARP(二)
  11. movelast对数据记录数有要求吗_客户验厂,电脑坏了,考勤记录数据可以自动生成找回来吗?...
  12. 主进程退出后子进程还会存在吗?_[docker]从一个实例,一窥docker进程管理
  13. 基于springboot的社区核酸检测统计管理系统
  14. 【Android 教程系列第 10 篇】史上最全的 Android 应用包名汇总,含主流应用商店包名,持续更新...
  15. 普通人也可以制作App
  16. 腐蚀rust服务器命令_腐蚀rust服务器命令一览 腐蚀rust有哪些命令
  17. c语言与或非,单片机avr c语言位运算 与或非 异或逻辑 运算介绍 详解
  18. Golang 定时器timer和ticker
  19. scala 编程(其五)集合,交差交差集
  20. 排列组合之生成排列_(:з」∠)_

热门文章

  1. 中国大飞机计划将振翅飞翔
  2. Promise为什么同时触发了then和catch
  3. java相对路径的书写
  4. C#调用WSDL接口
  5. Dynamics 365 for Sales: 门户网页模板的制作
  6. FTP服务基础与如何设置匿名访问FTP服务
  7. 【Quarkus技术系列】「云原生架构原理」在云原生时代下的Java“拯救者”是Quarkus,那云原生是什么呢?
  8. Kstry流程编排框架
  9. 创维E900-S-非高安_HI3798MV100_免拆或拆机短接强刷-当贝桌面卡刷固件包
  10. 栈和队列——小猫钓鱼