【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 ...
随机推荐
- iOS 学习 - 25 ImageIO 播放 GIF
一.给原生的 UIImageView 添加类别来支持 GIF 播放 GIF 动态图片文件中包含了一组图片及信息,信息主要记录着每一帧图片播放的时间,我们如果获取到了 gif 文件中所有的图片同时又获取 ...
- SQLite学习笔记(六)&&共享缓存
介绍 通常情况下,sqlite中每个连接都会一个独立的pager对象,pager对象中管理了该连接的缓存信息,通过pragma cache_size指令可以设置缓存大小,默认是2000个page,每个 ...
- 【转】Flex 布局语法教程
网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中 ...
- YARN DistributedShell源码分析与修改
YARN DistributedShell源码分析与修改 YARN版本:2.6.0 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 概述 2 YARN Distrib ...
- docker
docker pull centos docker images docker run -ti centos cat /etc/redhat-release ##################### ...
- Oracle基本数据类型
一 字符串类型 字符串数据类型还可以依据存储空间分为固定长度类型(CHAR/NCHAR) 和可变长度类型(VARCHAR2/NVARCHAR2)两种. 所谓固定长度:是指虽然输入的字段值小于该字段的限 ...
- POJ2186 Popular Cows [强连通分量|缩点]
Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 31241 Accepted: 12691 De ...
- UNIX系统基本结构
UNIX系统的基本结构如图所示.整个UNIX系统可分为五层:最底层是裸机,即硬件部分:第二层是UNIX的核心,它直接建立在裸机的上面,实现了操作系统重要的功能,如进程管理.存储管理.设备管理.文件管理 ...
- c语言中的scanf在java中应该怎么表达,Scanner类。
1 java是面向对象的语言 它没有像C语言中的scanf()函数,但是它的类库中有含有scanf功能的函数 2 java.util包下有Scanner类 Scanner类的功能与scanf类似 3 ...
- web端功能测试总结(一)
一.功能测试 1.1链接测试 链接是web应用系统的一个很重要的特征,主要是用于页面之间切换跳转,指导用户去一些不知道地址的页面的主要手段,链接测试一般关注三点: 1)链接是否按照既定指示那样,确实链 ...