get到了标记永久化

sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。

在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。

给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:

  1. 对于所有的 i∈[l,r]i∈[l,r],将 AiAi 变成 Ai+xAi+x。
  2. 对于所有的 i∈[l,r]i∈[l,r],将 AiAi 变成 ⌊Ai−−√⌋⌊Ai⌋。
  3. 对于所有的 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. 基础数据结构练习题的更多相关文章

  1. uoj #228. 基础数据结构练习题 线段树

    #228. 基础数据结构练习题 统计 描述 提交 自定义测试 sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧. 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手.于是她的 ...

  2. uoj#228 基础数据结构练习题

    题面:http://uoj.ac/problem/228 正解:线段树. 我们可以发现,开根号时一个区间中的数总是趋近相等.判断一个区间的数是否相等,只要判断最大值和最小值是否相等就行了.如果这个区间 ...

  3. uoj#228. 基础数据结构练习题(线段树区间开方)

    题目链接:http://uoj.ac/problem/228 代码:(先开个坑在这个地方) #include<bits/stdc++.h> using namespace std; ; l ...

  4. uoj#228. 基础数据结构练习题(线段树)

    传送门 只有区间加区间开方我都会--然而加在一起我就gg了-- 然后这题的做法就是对于区间加直接打标记,对于区间开方,如果这个区间的最大值等于最小值就直接区间覆盖(据ljh_2000大佬说这个区间覆盖 ...

  5. UOJ #228. 基础数据结构练习题 线段树 + 均摊分析 + 神题

    题目链接 一个数被开方 #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",st ...

  6. UOJ #228 - 基础数据结构练习题(势能线段树+复杂度分析)

    题面传送门 神仙题. 乍一看和经典题 花神游历各国有一点像,只不过多了一个区间加操作.不过多了这个区间加操作就无法再像花神游历各国那样暴力开根直到最小值为 \(1\) 为止的做法了,稍微感性理解一下即 ...

  7. 【UOJ#228】基础数据结构练习题 线段树

    #228. 基础数据结构练习题 题目链接:http://uoj.ac/problem/228 Solution 这题由于有区间+操作,所以和花神还是不一样的. 花神那道题,我们可以考虑每个数最多开根几 ...

  8. 【UOJ228】基础数据结构练习题(线段树)

    [UOJ228]基础数据结构练习题(线段树) 题面 UOJ 题解 我们来看看怎么开根? 如果区间所有值都相等怎么办? 显然可以直接开根 如果\(max-sqrt(max)=min-sqrt(min)\ ...

  9. 【uoj#228】基础数据结构练习题 线段树+均摊分析

    题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有三种:区间加.区间开根.区间求和. $n,m,a_i\le 100000$ . 题解 线段树+均摊分析 对于原来的两个数 $a$ ...

随机推荐

  1. express框架之1

    express框架: 1.依赖中间件 2.接受请求 get / post / use get('/地址' , function(req , resp ){}) post和use 同理 3.非破坏式 4 ...

  2. 「今日 GitHub 趋势」让全世界程序员体会中国的 12306 抢票狂潮

    [2018年1月7日 GitHub 趋势] No.1:yyx990803 / build-your-own-mint 单日 714 星 使用 Plaid,Google 表格和 CircleCI 构建您 ...

  3. 「开源」SpringCloud+vue搭建的商城项目

    最近在研究SpringCloud,看到一个基于SpringCloud+vue搭建的模拟商城项目.用来辅助学习SpringCloud企业级开发还是很有帮助的.强烈推荐!! 源码地址在最后. spring ...

  4. Vuex目录结构推荐

    目录结构如下: - src - store // 在src目录下 新建一个store文件夹 - mutations.js // mutations - mutaions_types.js // mut ...

  5. LCT 学习笔记

    LCT学习笔记 前言 自己定的学习计划看起来完不成了(两天没学东西,全在补题),决定赶快学点东西 于是就学LCT了 简介 Link/Cut Tree是一种数据结构,我们用它解决动态树问题 但是LCT不 ...

  6. re 模块的重新整理

    RE模块 import  re 的常用操作 查找 1. findall : ret = re.findall('\d+'.'sjkhk172按实际花费928') #正则表达式,待匹配的字符串,flag ...

  7. MVC ef 连接数据库

    1.创建数据库 2.创建表 <pre name="code" class="sql">CREATE TABLE [dbo].[Student]( [ ...

  8. 第5章 引用类型---JS红宝书书摘系列笔记

    在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起,描述的是一类对象所具有的属性和方法.而对象是某个特定引用类型的实例. 一.Object类型 可以通过Object构造函数创 ...

  9. 除虫记——有关WindowsAPI文件查找函数的一次压力测试

    作者:朱金灿 来源:http://blog.csdn.net/clever101 这里说的除虫是指排除bug的意思.今天排除了一个有意思的bug,其中的场景大致是这样的:现在你要统计一个文件夹下非隐藏 ...

  10. Linux下各文件夹的结构说明及用途介绍(转载)

    linux下各文件夹的结构说明及用途介绍: /bin:二进制可执行命令. /dev:设备特殊文件. /etc:系统管理和配置文件. /etc/rc.d:启动的配 置文件和脚本. /home:用户主目录 ...