【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 ...
随机推荐
- CSS background-color 、image 背景图片
背景颜色 background-color 语法: background-color:<color> 默认值:transparent 透明 适用于:所有元素 继承性:无 动画性:是 计算 ...
- select、poll、epoll区别总结
1 本质上都是同步I/O 三者都是I/O复用,本质上都属于同步I/O.因为三者只是负责通知应用程序什么时候数据准备好了,实际的I/O操作还是在由应用程序处理:如果是异步I/O的话,实际I/O由内核处理 ...
- Database 'xxxx' is being recovered. Waiting until recovery is finished.
巡检发现一个SQL SERVER Express 2005数据库备份时出现下面错误: Database 'xxxx' is being recovered. Waiting until recover ...
- 关于Thinkcmf中热门文章的使用
今天在做一个首页新闻列表页面的功能时候,因为要读取大量的新闻内容列表.如果每条数据都要从数据按照文章id和term_id来对应取值,无疑是很痛苦的. 然而机智如我,发现cmf框架中热门文章的用法: 在 ...
- 更改CentOS7的yum更新源
1. 备份现有源: mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak 2.下载163源 wget h ...
- linux init 启动顺序
redhat init大致启动过程 第一个运行的程序是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作.比如在设定了运行等级 “:id:3:initdefa ...
- 框架基础之Hibernate简介
框架基础之Hibernate简介 1.什么是Hibernate? Hibernate是一个开发源代码的对象关系映射框架,它对JDBC进行非常轻量级的对象封装,使得程序员可以随心所欲地使用对象编程思维来 ...
- [WPF系列]-数据邦定之DataTemplate 使用 DataTrigger 来应用属性值
使用 DataTrigger 来应用属性值 当前表示不会告诉我们某个 Task 是家庭任务还是办公室任务.记住 Task 对象拥有类型为 TaskType 的 TaskType 属性,该类型是一个枚举 ...
- Java报表工具FineReport导出EXCEL的四种API
在实际的应用中会经常需要将数据导出成excel,导出的方式除原样导出还有分页导出.分页分sheet导出和大数据量导出.对于excel 2003版,由于限制了每个sheet的最大行数和列数,大数据量导出 ...
- 聊天室(Java实现)
功能: 登录 若用户账号不存在,弹出错误 若用户密码错误,弹出错误 若用户账号已在线,弹出错误 注册 若用户已注册,弹出错误 聊天室 多人聊天,类似QQ里的群. 点击右侧的在线用户,可进行一对一聊天. ...