【线段树】uoj#228. 基础数据结构练习题
get到了标记永久化
sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。
在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。
给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:
- 对于所有的 i∈[l,r]i∈[l,r],将 AiAi 变成 Ai+xAi+x。
- 对于所有的 i∈[l,r]i∈[l,r],将 AiAi 变成 ⌊Ai−−√⌋⌊Ai⌋。
- 对于所有的 i∈[l,r]i∈[l,r],询问 AiAi 的和。
作为一个不怎么熟练的初学者,sylvia 想了好久都没做出来。而可怜酱又外出旅游去了,一时间联系不上。于是她决定向你寻求帮助:你能帮她解决这个问题吗。
输入格式
第一行两个数:n,mn,m。
接下来一行 nn 个数 AiAi。
接下来 mm 行中,第 ii 行第一个数 titi 表示操作类型:
若 ti=1ti=1,则接下来三个整数 li,ri,xili,ri,xi,表示操作一。
若 ti=2ti=2,则接下来三个整数 li,rili,ri,表示操作二。
若 ti=3ti=3,则接下来三个整数 li,rili,ri,表示操作三。
输出格式
对于每个询问操作,输出一行表示答案。
数据范围
对于所有数据,保证有 1≤li≤ri≤n,1≤Ai,xi≤1051≤li≤ri≤n,1≤Ai,xi≤105
时间限制:1s1s
空间限制:256MB
题目分析
考虑只有区间开方和区间求和的操作,那么注意到开根号几次后数就变为1了,于是可以暴力做下去(或者分块弄一弄?)。
然而问题麻烦在于还结合了区间加的操作,于是会出现形如898989->232323->898989的极端数据卡掉暴力区间下爬的方法。
注意到若区间最大值等于区间最小值时就等于区间赋值(或者区间减)操作,并且复杂度最坏的情况只会在最大值与最小值相差1的时候发生。
那么相当于只要在区间开方时特判一下就好了。
(从别人博客get到了永久化标记的写法(据说常数挺小?))
复杂度证明:UOJ 228 基础数据结构练习题
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = ; struct node
{
ll sum,mx,mn,tag;
}f[maxn<<];
int n,m; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
void pushup(int rt, int lens)
{
f[rt].sum = f[rt<<].sum+f[rt<<|].sum+1ll*f[rt].tag*lens;
f[rt].mx = std::max(f[rt<<].mx, f[rt<<|].mx)+f[rt].tag;
f[rt].mn = std::min(f[rt<<].mn, f[rt<<|].mn)+f[rt].tag;
}
void tagAdd(int rt, int lens, ll c)
{
f[rt].tag += c, f[rt].mn += c, f[rt].mx += c, f[rt].sum += 1ll*lens*c;
}
void build(int rt, int l, int r)
{
if (l==r){
f[rt].sum = f[rt].mx = f[rt].mn = read();
return;
}
int mid = (l+r)>>;
build(rt<<, l, mid), build(rt<<|, mid+, r);
pushup(rt, r-l+);
}
void updateAdd(int rt, int L, int R, int l, int r, ll c)
{
if (L <= l&&r <= R){
tagAdd(rt, r-l+, c);
return;
}
int mid = (l+r)>>;
if (L <= mid) updateAdd(rt<<, L, R, l, mid, c);
if (R > mid) updateAdd(rt<<|, L, R, mid+, r, c);
pushup(rt, r-l+);
}
void updateSqrt(int rt, int L, int R, int l, int r, ll tag)
{
if (L <= l&&r <= R){
ll s = sqrt(f[rt].mn+tag)+, t = sqrt(f[rt].mx+tag);
if ((f[rt].mx==f[rt].mn)||(f[rt].mx==f[rt].mn+&&s==t)){
tagAdd(rt, r-l+, s--f[rt].mn-tag); //这一步是用来保证复杂度的
return;
}
}
int mid = (l+r)>>;
if (L <= mid) updateSqrt(rt<<, L, R, l, mid, tag+f[rt].tag);
if (R > mid) updateSqrt(rt<<|, L, R, mid+, r, tag+f[rt].tag);
pushup(rt, r-l+);
}
ll query(int rt, int L, int R, int l, int r, ll tag)
{
if (L <= l&&r <= R)
return f[rt].sum+1ll*tag*(r-l+);
int mid = (l+r)>>;
ll ret = ;
if (L <= mid) ret = query(rt<<, L, R, l, mid, tag+f[rt].tag);
if (R > mid) ret += query(rt<<|, L, R, mid+, r, tag+f[rt].tag);
return ret;
}
int main()
{
n = read(), m = read();
build(, , n);
while (m--)
{
int opt = read();
if (opt==){
int l = read(), r = read(), c = read();
updateAdd(, l, r, , n, c);
}
if (opt==){
int l = read(), r = read();
updateSqrt(, l, r, , n, );
}
if (opt==){
int l = read(), r = read();
printf("%lld\n",query(, l, r, , n, ));
}
}
return ;
}
END
【线段树】uoj#228. 基础数据结构练习题的更多相关文章
- uoj #228. 基础数据结构练习题 线段树
#228. 基础数据结构练习题 统计 描述 提交 自定义测试 sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧. 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手.于是她的 ...
- uoj#228 基础数据结构练习题
题面:http://uoj.ac/problem/228 正解:线段树. 我们可以发现,开根号时一个区间中的数总是趋近相等.判断一个区间的数是否相等,只要判断最大值和最小值是否相等就行了.如果这个区间 ...
- uoj#228. 基础数据结构练习题(线段树区间开方)
题目链接:http://uoj.ac/problem/228 代码:(先开个坑在这个地方) #include<bits/stdc++.h> using namespace std; ; l ...
- uoj#228. 基础数据结构练习题(线段树)
传送门 只有区间加区间开方我都会--然而加在一起我就gg了-- 然后这题的做法就是对于区间加直接打标记,对于区间开方,如果这个区间的最大值等于最小值就直接区间覆盖(据ljh_2000大佬说这个区间覆盖 ...
- UOJ #228. 基础数据结构练习题 线段树 + 均摊分析 + 神题
题目链接 一个数被开方 #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",st ...
- UOJ #228 - 基础数据结构练习题(势能线段树+复杂度分析)
题面传送门 神仙题. 乍一看和经典题 花神游历各国有一点像,只不过多了一个区间加操作.不过多了这个区间加操作就无法再像花神游历各国那样暴力开根直到最小值为 \(1\) 为止的做法了,稍微感性理解一下即 ...
- 【UOJ#228】基础数据结构练习题 线段树
#228. 基础数据结构练习题 题目链接:http://uoj.ac/problem/228 Solution 这题由于有区间+操作,所以和花神还是不一样的. 花神那道题,我们可以考虑每个数最多开根几 ...
- 【UOJ228】基础数据结构练习题(线段树)
[UOJ228]基础数据结构练习题(线段树) 题面 UOJ 题解 我们来看看怎么开根? 如果区间所有值都相等怎么办? 显然可以直接开根 如果\(max-sqrt(max)=min-sqrt(min)\ ...
- 【uoj#228】基础数据结构练习题 线段树+均摊分析
题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有三种:区间加.区间开根.区间求和. $n,m,a_i\le 100000$ . 题解 线段树+均摊分析 对于原来的两个数 $a$ ...
随机推荐
- hdu 1695 GCD(容斥)
题目链接 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline int read() { , ...
- 51Nod 1043 幸运号码
#include <stdio.h> #include <algorithm> using namespace std; typedef long long ll; ; ][] ...
- Centos5.11 使用yum源
由于我是用的系统是Centos 5.11以停止更新很多年,故此yum也不能用,找了很多方法,最终yum能稳定的运行在Centos5.11上,下面开始一一讲解步骤: 1:首先更新yum源 地址:http ...
- Mysql 开启 Slow 慢查询
1:登录数据库查看是否已经开启了Slow慢查询: mysql> show variables like 'slow_query%'; 2:开启Mysql slow日志: 默认情况下slow_qu ...
- jave 计算音视频时长
File source = new File("视频.mp4"); Encoder encoder = new Encoder(); try { MultimediaInfo in ...
- python使用rabbitmq实现简单的消息转发
准备: 1.下载elang语言的支持环境http://www.erlang.org/download.html (rabbitmq使用它开发的) 2.下载rabbitmq软件http://www.ra ...
- nodejs下express+ejs环境搭建
nodejs下express+ejs环境搭建 分类: Nodejs 1.进入需要创建项目的目录 cd F:\nodeCode 2.创建一个带ejs模板工程,工程名为haha e ...
- java设计模式--建造模式
建造模式 建造模式属于对象创建型模式,建造模式的目的为将复杂对象的构建过程与其部件实现方式分离,使得同样的构建过程可以有不同的表示,同时相同的构建过程也能够适用于不同的部件实现方式. 建造模式的适用性 ...
- LogBack日志小记
优势 看了一下Logback的官方文档,说换成LogBack的原因大概有一下几个: 1. 说是logBack的设计开发和log4j是同一批人员,重写了内核,习惯上总体跟log4j一样,不会有太多生疏感 ...
- 解决部分浏览器不能显示itext生成的PDF文件文本域内容问题
利用Itext可以实现pdf的高效动态生成,但在实践过程中遇到了一个问题: 即itext利用map中的值设置到pdf模板上建立的文本域中时:能成功生成,但是在部分浏览器上(360,QQ,等浏览器)无法 ...