【UOJ#228】基础数据结构练习题 线段树
#228. 基础数据结构练习题
题目链接:http://uoj.ac/problem/228
Solution
这题由于有区间+操作,所以和花神还是不一样的。 花神那道题,我们可以考虑每个数最多开根几次就会成1,而这个必须利用开根的性质
我们维护区间最大、最小、和。区间加操作可以直接做。
区间开方操作需要特殊考虑。
首先对于一个区间,如果这个区间的所有数取$x=\left \lfloor \sqrt{x} \right \rfloor$值一样,那么就可以直接区间覆盖。
分析上述过程,一个区间可以直接覆盖,当这个区间的差值满足一个特定的范围。 而每次开方这个差值就会减少,可以证明这样开方$lg^{2}$次就会全部为1
所以剩下的我们就可递归下去。
这样的话,区间+操作,就相当于重置了这个差值,所以复杂度还是科学的。
但是有一种情况出现问题。
上述是每次开方后,差值减小,但是有开方后差值不变的情况。 例如 3 4 3 4 3 4 3 4
即$a$,$b$当$b$为完全平方数,$a=b-1$时。这样开方完差值还是1,然后区间+2就又变回来了。 这样上述就卡成了暴力。
那么我们把这种情况特殊考虑。 这样可以转化为一个区间-的操作。剩下的暴力递归,这样就可以了。
时间复杂度是$O(NlogNlg^2{N})$
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 100010
int N,M,a[MAXN];
namespace SegmentTree
{
struct SegmentTreeNode{int l,r,cov; LL tag,sum,maxx,minx;}tree[MAXN<<];
#define ls now<<1
#define rs now<<1|1
inline void Update(int now)
{
tree[now].sum=tree[ls].sum+tree[rs].sum;
tree[now].maxx=max(tree[ls].maxx,tree[rs].maxx);
tree[now].minx=min(tree[ls].minx,tree[rs].minx);
}
inline void cover(int now,int D)
{
tree[now].cov=D; tree[now].tag=;
tree[now].minx=tree[now].maxx=D;
tree[now].sum=D*(tree[now].r-tree[now].l+);
}
inline void modify(int now,LL D)
{
tree[now].tag+=D;
tree[now].minx+=D; tree[now].maxx+=D; tree[now].sum+=(tree[now].r-tree[now].l+)*D;
}
inline void PushDown(int now)
{
if (tree[now].l==tree[now].r) return;
if (tree[now].cov!=-)
cover(ls,tree[now].cov),cover(rs,tree[now].cov),tree[now].cov=-;
if (tree[now].tag!=)
modify(ls,tree[now].tag),modify(rs,tree[now].tag),tree[now].tag=;
}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r; tree[now].cov=-;
if (l==r) {tree[now].sum=tree[now].maxx=tree[now].minx=a[l]; return;}
int mid=(l+r)>>;
BuildTree(ls,l,mid); BuildTree(rs,mid+,r);
Update(now);
}
inline void Modify(int now,int L,int R,int D)
{
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) {modify(now,D); return;}
int mid=(l+r)>>;
if (L<=mid) Modify(ls,L,R,D);
if (R>mid) Modify(rs,L,R,D);
Update(now);
}
inline void Change(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r)
{
if ((int)sqrt(tree[now].maxx)==(int)sqrt(tree[now].minx))
{cover(now,(int)sqrt(tree[now].maxx)); return;}
if (tree[now].maxx==tree[now].minx+)
{modify(now,(int)sqrt(tree[now].minx)-tree[now].minx); return;}
if (l!=r) Change(ls,L,R),Change(rs,L,R);
Update(now);
return;
}
int mid=(l+r)>>;
if (L<=mid) Change(ls,L,R);
if (R>mid) Change(rs,L,R);
Update(now);
}
inline LL Query(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) return tree[now].sum;
int mid=(l+r)>>; LL re=;
if (L<=mid) re+=Query(ls,L,R);
if (R>mid) re+=Query(rs,L,R);
return re;
}
}
int main()
{
N=read(),M=read();
for (int i=; i<=N; i++) a[i]=read();
SegmentTree::BuildTree(,,N);
while (M--)
{
int opt=read(),l=read(),r=read(),D;
switch (opt)
{
case : D=read(),SegmentTree::Modify(,l,r,D); break;
case : SegmentTree::Change(,l,r); break;
case : printf("%lld\n",SegmentTree::Query(,l,r)); break;
}
// for (int i=1; i<=N; i++) printf("%d ",SegmentTree::Query(1,i,i)); puts("=================");
}
return ;
}
【UOJ#228】基础数据结构练习题 线段树的更多相关文章
- uoj #228. 基础数据结构练习题 线段树
#228. 基础数据结构练习题 统计 描述 提交 自定义测试 sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧. 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手.于是她的 ...
- uoj#228. 基础数据结构练习题(线段树区间开方)
题目链接:http://uoj.ac/problem/228 代码:(先开个坑在这个地方) #include<bits/stdc++.h> using namespace std; ; l ...
- UOJ #228. 基础数据结构练习题 线段树 + 均摊分析 + 神题
题目链接 一个数被开方 #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",st ...
- 【线段树】uoj#228. 基础数据结构练习题
get到了标记永久化 sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧. 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手.于是她的好朋友九条可怜酱给她出了一道题. 给出一 ...
- uoj#228 基础数据结构练习题
题面:http://uoj.ac/problem/228 正解:线段树. 我们可以发现,开根号时一个区间中的数总是趋近相等.判断一个区间的数是否相等,只要判断最大值和最小值是否相等就行了.如果这个区间 ...
- 【uoj#228】基础数据结构练习题 线段树+均摊分析
题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有三种:区间加.区间开根.区间求和. $n,m,a_i\le 100000$ . 题解 线段树+均摊分析 对于原来的两个数 $a$ ...
- uoj#228. 基础数据结构练习题(线段树)
传送门 只有区间加区间开方我都会--然而加在一起我就gg了-- 然后这题的做法就是对于区间加直接打标记,对于区间开方,如果这个区间的最大值等于最小值就直接区间覆盖(据ljh_2000大佬说这个区间覆盖 ...
- UOJ #228 - 基础数据结构练习题(势能线段树+复杂度分析)
题面传送门 神仙题. 乍一看和经典题 花神游历各国有一点像,只不过多了一个区间加操作.不过多了这个区间加操作就无法再像花神游历各国那样暴力开根直到最小值为 \(1\) 为止的做法了,稍微感性理解一下即 ...
- [UOJ228] 基础数据结构练习题 - 线段树
考虑到一个数开根号 \(loglog\) 次后就会变成1,设某个Node的势能为 \(loglog(maxv-minv)\) ,那么一次根号操作会使得势能下降 \(1\) ,一次加操作最多增加 \(l ...
随机推荐
- ToolBar和DrawerLayout的使用实现侧拉栏抽屉的开闭
1.如图可以看到textColorPrimary,colorPrimary,colorPrimaryDark,navigationBarColor等颜色属性代表的相应位置,如下图 2.具体属性在res ...
- 【ASM】ASMSNMP用户已存在
[ASM]ASMSNMP用户已存在 During Oracle Grid Infrastructure for a cluster installation, the ASMSNMP account ...
- 启动mysql时显示:/tmp/mysql.sock 不存在的解决方法
启动mysql时显示:/tmp/mysql.sock 不存在的解决方法 启动mysql时报错的解决(mysql 5.0.45 redhat as 43) ====================== ...
- 使用 expect 命令执行自动分发系统
一.命令 except 实例详解 1. 介绍 expect 使用场景 expect可以让我们实现自动登录远程机器,并且可以实现自动远程执行命令.当然若是使用不带密码的密钥验证同样可以实现自动登录和自动 ...
- 002.php安装(lnmp)
搭建lnmp环境时,需要先安装mysql,再安装php,而nginx安装顺序无所谓,nginx与php之间的联系需要手动配置 一.php下载和配置“安装环境“ [root@huh ~]# cd /us ...
- js中取得当前加载的js的src地址
在很多js框架中看到过,如果要动态加载框架内部的其他js,加载的时候加载的地址经常是一个相对的地址,只能是这样了哦,因为框架根本不知道用此框架的用户,将框架js文件放的具体目录,所以框架中一般会采用如 ...
- Walle - 瓦力上线部署系统搭建攻略
背景知识:Walle - 瓦力是一个支持svn.git.多用户.多项目.多环境同时部署的上线部署系统,http://www.oschina.net/news/68610/walle-0-9-2 实验系 ...
- Redis学习和环境搭建
基本的redis教程,搭建,可以参照下面任一教程: 地址一:http://www.yiibai.com/redis/redis_quick_guide.html 地址二:http://www.runo ...
- Cmake的交叉编译
http://www.cmake.org/Wiki/CMake_Cross_Compiling
- docker
docker pull centos docker images docker run -ti centos cat /etc/redhat-release ##################### ...