前言:

本来以为很难打的,没想到主干一次就打对了,然而把输入的b和d弄混了,这sb错误调了两个小时。。。

解析:

神奇的线段树。注意到有一个性质,无论怎么割草,生长速度快的一定不会比生长速度慢的矮。因此可以先排个序,然后就可以用线段树维护了。

首先维护区间的sum,这个很显然。

然后会发现一个问题,每次割草时,不知道从哪里开始割。这时可以运用线段树上二分的思想,维护一个区间max,每次只要查询区间中第一个大于上限的位置即可。

还有区间赋值和区间加的标记,这个就是细节问题了。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500000+10;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
char buf[1 << 20], *p1, *p2;
int n,m;
ll sum[maxn];
ll b,d,last,ans;
int a[maxn];
struct Segment_tree{
ll sum,lazyfz,max,lazyadd;
}tree[maxn<<2];
bool cmp(int x,int y){
return x<y;
}
void build(int rt,int l,int r){
tree[rt].lazyfz=-1;
if(l==r) return;
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
void update(int rt,int l,int r,ll x){
tree[rt].sum=x*(r-l+1);
tree[rt].max=x;
tree[rt].lazyfz=x;
tree[rt].lazyadd=0;
}
void updateadd(int rt,int l,int r,ll x){
tree[rt].sum+=x*(sum[r]-sum[l-1]);
tree[rt].max+=x*a[r];
tree[rt].lazyadd+=x;
}
void pushdown(int rt,int l,int r){
int mid=(l+r)>>1;
if(tree[rt].lazyfz!=-1){
update(rt<<1,l,mid,tree[rt].lazyfz);
update(rt<<1|1,mid+1,r,tree[rt].lazyfz);
tree[rt].lazyfz=-1;
}
if(tree[rt].lazyadd){
updateadd(rt<<1,l,mid,tree[rt].lazyadd);
updateadd(rt<<1|1,mid+1,r,tree[rt].lazyadd);
tree[rt].lazyadd=0;
}
}
void mm(ll x){
pushdown(1,1,n);
updateadd(1,1,n,x);
}
int query(int rt,int l,int r,int s,int t,ll x){//查找第一个大于x的数,如果没有,返回-1;
if(l==r) return tree[rt].max>x ? l : -1 ;
if(tree[rt].max<=x) return -1;
pushdown(rt,l,r);
int mid=(l+r)>>1;
if(t<=mid) return query(rt<<1,l,mid,s,t,x);
if(s>mid) return query(rt<<1|1,mid+1,r,s,t,x);
int res=query(rt<<1,l,mid,s,t,x);
if(res!=-1) return res;
return query(rt<<1|1,mid+1,r,s,t,x);
}
ll querysum(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[rt].sum;
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(t<=mid) return querysum(rt<<1,l,mid,s,t);
if(s>mid) return querysum(rt<<1|1,mid+1,r,s,t);
return querysum(rt<<1,l,mid,s,t)+querysum(rt<<1|1,mid+1,r,s,t);
}
void pushup(int rt){
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
tree[rt].max=max(tree[rt<<1].max,tree[rt<<1|1].max);
}
void modify(int rt,int l,int r,int s,int t,ll x){
if(s<=l&&r<=t){
update(rt,l,r,x);
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(s<=mid) modify(rt<<1,l,mid,s,t,x);
if(t>mid) modify(rt<<1|1,mid+1,r,s,t,x);
pushup(rt);
}
void Solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
build(1,1,n);
for(int i=1;i<=m;++i){
scanf("%lld%lld",&b,&d);
mm(b-last);
last=b;
int x=query(1,1,n,1,n,d);
if(x!=-1){
ans=querysum(1,1,n,x,n);
ans-=d*(n-x+1);
modify(1,1,n,x,n,d);
}else ans=0;
printf("%lld\n",ans);
}
}
int main(){
Solve();
return 0;
}

[火星补锅] siano 神奇的线段树的更多相关文章

  1. [火星补锅] 水题大战Vol.2 T1 && luogu P1904 天际线 题解 (线段树)

    前言: 当时考场上并没有想出来...后来也是看了题解才明白 解析: 大家(除了我)都知道,奇点和偶点会成对出现,而出现的前提就是建筑的高度突然发生变化.(这个性质挺重要的,我之前没看出来) 所以就可以 ...

  2. [火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解

    前言: 这题感觉还是很有意思.离线思路很奇妙.可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了. 解析: 题目十分清真. 求一段连续区间内的所有点和某个给出的点的Lca的深度和. 首先可以 ...

  3. CodeForces-213E:Two Permutations(神奇的线段树+hash)

    Rubik is very keen on number permutations. A permutation a with length n is a sequence, consisting o ...

  4. [火星补锅] 水题大战Vol.2 T2 && luogu P3623 [APIO2008]免费道路 题解

    前言: 如果我自己写的话,或许能想出来正解,但是多半会因为整不出正确性而弃掉. 解析: 这题算是对Kruskal的熟练运用吧. 要求一颗生成树.也就是说,最后的边数是确定的. 首先我们容易想到一个策略 ...

  5. [火星补锅] 非确定性有穷状态决策自动机练习题Vol.1 T3 第K大区间 题解

    前言: 老火星人了 解析: 很妙的二分题.如果没想到二分答案.. 很容易想到尝试用双指针扫一下,看看能不能统计答案. 首先,tail指针右移时很好处理,因为tail指针右移对区间最大值的影响之可能作用 ...

  6. HDU 1823 Luck and Love(二维线段树)

    之前只知道这个东西的大概概念,没具体去写,最近呵呵,今补上. 二维线段树 -- 点更段查 #include <cstdio> #include <cstring> #inclu ...

  7. [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

    题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...

  8. BZOJ3711 PA2014Druzyny(动态规划+cdq分治+线段树)

    显然可以dp:设f[i]为前i个人最多能分多少组,则f[i]=max{f[j]}+1 (cmax<=i-j<=dmin). 容易发现d的限制是一段连续区间,二分或者随便怎么搞都行.c则有点 ...

  9. 普及向 ZKW线段树!

    啊,是否疲倦了现在的线段树 太弱,还递归! 那我们就欢乐的学习另外一种神奇的线段树吧!(雾 他叫做zkw线段树   这个数据结构灰常好写(虽然线段树本身也特别好写……) 速度快(貌似只在单点更新方面比 ...

随机推荐

  1. C# Dapper基本三层架构使用 (四、WinForm UI层)

    UI层主要功能是显示数据和接受传输用户的数据,可以在为网站的系统运行提供交互式操作界面,表示层的应用方式比较常见,例如Windows窗体和Web页面. 在项目中增加WinForm应用程序,结构如下 添 ...

  2. Spring5(七)——AOP注解

    一.AOP注解 1.介绍 上一节介绍了 AspectJ 框架如何实现 AOP,具体的实现方式是通过 xml 来进行配置的.xml 方式思路清晰,便于理解,但是书写过于麻烦.这一节介绍注解的方式来进行 ...

  3. SpringBoot系列——附件管理:整合业务表单实现上传、回显、下载

    前言 日常开发中,大多数项目都会涉及到附件上传.回显.下载等功能,本文记录封装通用附件管理模块,并与业务模块进行整合实现上传.回显.下载 我们之前已经对文件上传下载有过记录,传送门:基于"f ...

  4. java版gRPC实战之七:基于eureka的注册发现

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. 3.17学习总结.listview用法总结

    今天复习了listview控件的用法. 1.activity_main.xml 中的代码,如下: <?xml version="1.0" encoding="utf ...

  6. scrum项目冲刺_day09总结

    摘要:今日完成任务. 1.短信服务完成(由于使用免费的接口,导致部分手机会收到垃圾短信) 2.注册登录完成 3.导航还在进行 总任务: 一.appUI页面(已完成) 二.首页功能: 1.图像识别功能( ...

  7. 【Python学习】print语句

    一.print 可以向屏幕上输出信息,print 后面一个空格再加上''中间放入要输出的内容. 二.print可以用逗号分隔语句,但是每有一个逗号就会出来一个空格. 1 >>> pr ...

  8. Jenkins 进阶篇 - 任务关联

    有时候我们的一个任务里面会进行很多的步骤,例如构建一个后端的 Java 服务,可能会有代码静态扫描,静态扫描通过后会打包成 jar 或者 war 文件,打包成功后可能还会对制品进行存档备份,然后可能会 ...

  9. PHP中的一些杂项函数学习

    今天来学习的这些杂项函数在官方文档中都是放在一个杂项扩展中的,其实这些函数都并不是什么什么特别的扩展,也不需要安装什么东西就可以使用,它们就是一些简单的功能函数而已.当然,其中不少内容也是我们经常会使 ...

  10. 安装 MongoDb

    下面具体说下MongoDB安装之后的一些配置操作 [声明]我的安装路径是:C:\Program Files\MongoDB\Server\3.4 1. 创建数据库路径(data目录).日志路径(log ...