【线段树】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$ ...
随机推荐
- 解决web项目无法部署到eclipse配置的本地tomcat
一.发现问题 在eclipse中新建Dynamic Web Project,配置好本地的tomcat并写好代码后选择Run on Server,但运行后发现在tomcat的安装目录下的webapps并 ...
- Zynq7000开发系列-2(VMware与Ubuntu安装使用)
一.前言 在嵌入式开发中,是无法避免使用Linux系统的,因为在开发之前必须先搭建起交叉编译环境,而后关于Bootloader.Linux Kernel的裁剪移植,File system的制作,底层驱 ...
- Codeforces Round #533(Div. 2) C.Ayoub and Lost Array
链接:https://codeforces.com/contest/1105/problem/C 题意: 给n,l,r. 一个n长的数组每个位置可以填区间l-r的值. 有多少种填法,使得数组每个位置相 ...
- Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined) A
Description There are literally dozens of snooker competitions held each year, and team Jinotega tri ...
- mysql 维护添加远程主机访问
https://www.cnblogs.com/JNUX/p/6936548.html
- 解决java.lang.NoClassDefFoundError: javax/xml/rpc/service错误的方法
最近在做WebService项目,本地测试没有问题,打算部署到服务器上,但是部署后,访问时出现了如下图1的错误: 图1 图1报的是没有找到定义的类的错误.刷新页面有又出现了另外“新”的错误: 图2 根 ...
- P3375 【模板】KMP字符串匹配(全程注释,简单易懂)
题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[ ...
- CSS布局之-强大的负边距
css中的负边距(negative margin)是布局中的一个常用技巧,只要运用得合理常常会有意想不到的效果.很多特殊的css布局方法都依赖于负边距,所以掌握它的用法对于前端的同学来说,那是必须的. ...
- 严重:The web application [web01] appears to have started a thread named ...
Tomcat报错 严重:The web application [web01] appears to have started a thread named [PooledThread-1] but ...
- [总结].net操作MongoDb通用基础类1:
public class MongoDBHelper { //定义Mongo服务 private MongoServer mongo = null; //获取databaseName对应的数据库,不存 ...