HDU 6315 Naive Operations 【势能线段树】
<题目链接>
题目大意:
给出两个序列,a序列全部初始化为0,b序列为输入值。然后有两种操作,add x y就是把a数组[x,y]区间内全部+1,query x y是查询[x,y]区间内∑[ai/bi]。([ai/bi]代表ai/bi后向下取整)
解题分析:
首先,如果每次+1都暴力更新到每个叶子节点肯定会超时,但是如果不更新到叶子节点又不好维护每个节点对应区间 ∑[ai/bi] 的值,所以我们可以每个节点都维护四个值。sum值代表这个区间每个节点整数部分的所有数之和,lazy进行懒惰标记,避免每次更新到叶子节点,mxa记录该区间内分子的最大值,mnb记录该区间内分母的最小值。之所以要维护这两个最大最小值是因为,当进行区间整体+1操作的时候,如果该区间内最大的分子都小于分母时,说明这个区间在进行+1操作后,并没有对该区间的sum值做出贡献,所以此时就可以将这个+1操作lazy到这个节点;但是如果对区间整体+1后,最大分子大于等于最小分母,此时,就需要继续向下更新,直到找到那个(或者几个)分子大于等于分母的根节点,然后将该节点的sum+1,同时将b值加上原始的brr[l]值(其实我不太明白这一步为什么要这么做,我觉的这步等效于该点的mxa值-该点的mnb值啊,然而这样改了以后超时 T_T)。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define Lson rt<<1,l,mid
#define Rson rt<<1|1,mid+1,r
const int M =1e5+; int n,m;
struct Tree{
int lazy,sum;
int mxa,mnb;
}tr[M<<];
int brr[M]; void Pushdown(int rt){
if(tr[rt].lazy){
int tmp=tr[rt].lazy;
tr[rt<<].lazy+=tmp,tr[rt<<|].lazy+=tmp;
tr[rt<<].mxa+=tmp,tr[rt<<|].mxa+=tmp;
tr[rt].lazy=;
}
}
void Pushup(int rt){
tr[rt].sum=tr[rt<<].sum+tr[rt<<|].sum;
tr[rt].mxa=max(tr[rt<<].mxa,tr[rt<<|].mxa); //维护该区间内分子的最大值和分母的最小值
tr[rt].mnb=min(tr[rt<<].mnb,tr[rt<<|].mnb);
}
void build(int rt,int l,int r){ //初始化
tr[rt].lazy=;
if(l==r){
tr[rt].mxa=tr[rt].sum=;
tr[rt].mnb=brr[l];
return;
}
int mid=(l+r)>>;
build(Lson);
build(Rson);
Pushup(rt);
}
void update(int rt,int l,int r,int L,int R){ //这个函数是本题的关键
if(L<=l&&r<=R){
tr[rt].mxa++;
if(tr[rt].mxa<tr[rt].mnb){ //如果最大的分子小于最大的分母,说明这个区间内的所有叶子在分子+1之后,没有对sum值多做出贡献,所以我们先将这个操作lazy在这个节点
tr[rt].lazy++;
return;
}
if(l==r&&tr[rt].mxa>=tr[rt].mnb){ //如果向下找到了那个分子大于等于分母的叶子节点,那么该节点贡献+1,且将分母加上最初始的防御值,相当于将该真分数的整数部分提出后,再将其变成假分数,方便以后继续统计贡献
tr[rt].sum++;
tr[rt].mnb+=brr[l]; //我觉的这一步应该等效于tr[rt].mxa-=tr[rt].mnb啊,然而这样改了以后超时
return;
}
}
Pushdown(rt);
int mid=(l+r)>>;
if(L<=mid)update(Lson,L,R);
if(R>mid)update(Rson,L,R);
Pushup(rt);
}
int query(int rt,int l,int r,int L,int R){ //查询该区间内所有数的整数部分之和
if(L<=l&&r<=R)return tr[rt].sum;
Pushdown(rt);
int ans=;
int mid=(l+r)>>;
if(L<=mid)ans+=query(Lson,L,R);
if(R>mid)ans+=query(Rson,L,R);
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=;i<=n;i++)
scanf("%d",&brr[i]);
build(,,n);
char op[];
while(m--){
int x,y;
scanf("%s%d%d",&op,&x,&y);
if(op[]=='a')update(,,n,x,y);
else printf("%d\n",query(,,n,x,y));
}
}
return ;
}
2018-10-15
HDU 6315 Naive Operations 【势能线段树】的更多相关文章
- HDU 6315 Naive Operations(线段树+区间维护)多校题解
题意:a数组初始全为0,b数组题目给你,有两种操作: 思路:dls的思路很妙啊,我们可以将a初始化为b,加一操作改为减一,然后我们维护一个最小值,一旦最小值为0,说明至少有一个ai > bi,那 ...
- HDU 6351 Naive Operations(线段树)
题目: http://acm.hdu.edu.cn/showproblem.php?pid=6315 Naive Operations Time Limit: 6000/3000 MS (Java/O ...
- 杭电多校第二场 hdu 6315 Naive Operations 线段树变形
Naive Operations Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 502768/502768 K (Java/Other ...
- HDU-DuoXiao第二场hdu 6315 Naive Operations 线段树
hdu 6315 题意:对于一个数列a,初始为0,每个a[ i ]对应一个b[i],只有在这个数字上加了b[i]次后,a[i]才会+1. 有q次操作,一种是个区间加1,一种是查询a的区间和. 思路:线 ...
- HDU 6315 Naive Operations(线段树区间整除区间)
Problem DescriptionIn a galaxy far, far away, there are two integer sequence a and b of length n.b i ...
- HDU - 6315 Naive Operations (线段树+思维) 2018 Multi-University Training Contest 2
题意:数量为N的序列a和b,a初始全为0,b为给定的1-N的排列.有两种操作:1.将a序列区间[L,R]中的数全部+1:2.查询区间[L,R]中的 ∑⌊ai/bi⌋(向下取整) 分析:对于一个位置i, ...
- HDU 6315 Naive Operations(线段树+复杂度均摊)
发现每次区间加只能加1,最多全局加\(n\)次,这样的话,最后的答案是调和级数为\(nlogn\),我们每当答案加1的时候就单点加,最多加\(nlogn\)次,复杂度可以得当保证. 然后问题就是怎么判 ...
- hdu 6315 Naive Operations (2018 Multi-University Training Contest 2 1007)
Naive Operations Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 502768/502768 K (Java/Other ...
- HDU 6315: Naive Operations
Naive Operations Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 502768/502768 K (Java/Other ...
- HDU-6315:Naive Operations(线段树+思维)
链接:HDU-6315:Naive Operations 题意: In a galaxy far, far away, there are two integer sequence a and b o ...
随机推荐
- 2019 Multi-University Training Contest 3 Find the answer (离散化+二分+树状数组)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609 题目大意:给定一个含有n个数的序列,还有一个m,对于每个i(1<=i<=n)求出最少 ...
- opencv windows源码编译
WITH_QT//H:\software\programming\qt\5.12.3\mingw73_32\lib\cmake 5.6的路径要改这样 WITH_OPENGL 编译器mingw32-m ...
- django 多表查询并返回结果
(不喜勿喷,个人记录) 问题,有两张关联的表,表B的api_id关联表A的id 我想在页面上返回两张表查询之后的共同结果? 因为两张表的id是一样的,就先获取到表A的对象,然后拿表A的对象id当做表B ...
- deque的简单使用
depue 是python提供的一个数据结构,线程安全,功能比list强大 from collections import deque user_list = ['admin', 'root'] us ...
- Linux 系统参数优化
修改系统所有进程可打开的文件数量 sysctl -w fs.file-max=2097152sysctl -w fs.nr_open=2097152 > vi /etc/sysctl.conff ...
- 小米笔记本pro版bios经常找不到硬盘
自从买了小米笔记本,对小米的印象大大折扣,bios经常找不到硬盘,关机,重启,就好了. 到小米售后,售后说是系统坏了,我说bios里都找不到.他说,系统坏了也会出现这个情况.我说好吧.重做后,没用几天 ...
- [STL]lower_bound&upper_bound
源码 lower_bound template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardI ...
- js点击获取—通过JS获取图片的绝对对坐标位置
一.通过JS获取鼠标点击时图片的相对坐标位置 源代码如下所示: <!DOCTYPE html> <html lang="en"> <head> ...
- HTML基础入门学习准备篇
在学习前端的开始,让我们一起来了解什么是HTML5时代的大前端开发和全栈开发的定义 传统的前端:切图-标签和样式-实现效果 H5时代的前端: 一.需要各端的兼容开发 二.可以用于APP开发和移动站点的 ...
- C++ 得到系统时间
Time::Time() {//得到系统时间 初始化 time_t t; t=time(NULL); tm *lt; lt=localtime(&t); hour=lt->tm_hour ...