【线段树】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$ ...
随机推荐
- ADO学途 two day
代码实现的参照性在学习程序中占了关键比重,最基本的都一直无法运行成功,那就无法深入 研究.实现winfrom功能的要点之一实践中获取原理:不清楚代码的一些原理,即使copy过来,大多也 存无法运行的情 ...
- Hexo - CNAME文件在每次部署后就没了
问题 一般我们会将Hexo博客搭建到Github上,如果在Github上为其配置一个自定义的域名时,会自动在项目仓库根目录下新添加一个CNAME文件.但是这里有个问题,如果将Hexo博客重新部署一遍后 ...
- Tomcat - ClassFormatException的解决方法
问题与分析 在使用Tomcat7运行web项目时报错如下: 严重: Compilation error org.eclipse.jdt.internal.compiler.classfmt.Class ...
- [Python]'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape 错误
f = open('C:\Users\xu\Desktop\ceshi.txt') 这时报标题的错误信息 f = open(r'C:\Users\xu\Desktop\ceshi.txt') 改成这个 ...
- java实现打印正三角,倒三角
正三角代码: package BasicType; /** * 封装一个可以根据用户传入值来打印正三角的方法 * @author Administrator */ public class Enme ...
- php—常见设计模式
工厂模式 /** * 工厂方法或者类生成对象,而不是在代码中直接new * * 修改类名的时候,不需要每一个实例化语句都修改 * 只需要修改对应的工厂方法 * * Class Factory * @p ...
- JAVA常用知识总结(十四)——Servlet
Servlet属于线程安全的吗? Servlet不是线程安全的! 谈谈转发和重定向的区别 请求转发: request.getRequestDispatcher("/king_l2lu.jsp ...
- 连接sql server、插入数据、从数据库获取时间(C#)
using System; using System.Data.SqlClient; namespace Test { //连接数据库 public class Connection { privat ...
- Json的详细用法
参考博客:https://www.cnblogs.com/haiyan123/p/7829080.html 1.json(Javascript Obiect Notation,JS对象标记)是一种 ...
- MyBatis的数据库操作
MyBatis的数据库操作 大学毕业有一段时间了,作为一名没有任何开发工作经验的大专毕业生想找到一份软件开发的工作确实很难,但我运气还算不错,应聘上一份java web开发的工作.作为一名新人,老板给 ...