SqrtTree学习笔记
散步的时候yy区间最值的不同分块做法,发现单点修改\(O(\sqrt{n})\)查询\(O(1)\)的做法不是很会?
于是yy了一个奇怪做法,写出来看看。
考虑查询的时候两端的散点可以用前后缀最值查出来,所以只需要考虑中间的块。
中间这些块似乎比较恶心,不知道怎么做。
于是我们把每一个块的最值拎出来作为一个点,再分一次块,就成功地用\(O(1)\)的时间把问题变成了根号级别的子问题。
于是分块套分块套分块套……,似乎很对?
如果左右端点都在同一个块内那么不是很好玩,就对每一个块里面也分块,也是一个根号级别的子问题。
于是查询\(T(n)=T(\sqrt{n})+O(1)=O(\log \log n)\)。
那么修改的时候呢?要更新这一个块里面的分块、更新总体的分块、更新前后缀,好像就是\(T(n)=2T(\sqrt{n})+\sqrt{n}\),也就是\(O(\sqrt{n})\)的。
复杂度一脸正确?
然后就被大佬摔在脸上:你这个东西跟sqrt-tree一模一样……
不过hz大佬改了一下,发现只需要分两层,在第二层块数是\(O(n^{\frac 1 4})\)的,于是可以直接暴力维护任意两个块中间的最值。于是就真的是\(O(\sqrt{n})-O(1)\)了。这样预处理的时间变成了\(O(n^{\frac 5 4})\),但有什么关系呢?反正它除了做模板题以外好像还干不了什么
把hz改后的版本的代码写了出来并且封装了。感觉这东西应该也可以支持\(O(\sqrt{n}+\log n)\)做区间赋值的,打几个标记就可以了,不过懒得写了……(这点应该比正常的SqrtTree优?)
代码以GSS3为例,由于上不了SPOJ所以没有测,但是拍上了。
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 233333
#define S 400
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
template<typename hh>struct MySqrtTree
{
struct WTF
{
int m;
vector<hh>a;
int cnt,B;
hh mx1[25][25];
hh mx2[25][25][25];
vector<int>L,R,id;
vector<hh>pre,suf;
void init(int type)
{
B=sqrt(m),cnt=(m-1)/B+1;
L.resize(cnt+5),R.resize(cnt+5),id.resize(m+5);
pre.resize(m+5),suf.resize(m+5);
rep(i,1,cnt) L[i]=R[i-1]+1,R[i]=min(L[i]+B-1,m);
rep(i,1,cnt) rep(j,L[i],R[i]) id[j]=i;
rep(i,1,cnt) pre[L[i]]=a[L[i]],suf[R[i]]=a[R[i]];
rep(i,1,cnt) rep(j,L[i]+1,R[i]) pre[j]=pre[j-1]+a[j];
rep(i,1,cnt) drep(j,R[i]-1,L[i]) suf[j]=a[j]+suf[j+1];
if (type) return;
rep(i,1,cnt) rep(j,L[i],R[i])
{
hh cur=mx2[i][j-L[i]][j-L[i]]=a[j];
rep(k,j+1,R[i])
cur=cur+a[k],mx2[i][j-L[i]][k-L[i]]=cur;
}
rep(j,1,cnt) { hh cur=mx1[j][j]=mx2[j][0][R[j]-L[j]]; rep(k,j+1,cnt) cur=cur+mx2[k][0][R[k]-L[k]],mx1[j][k]=cur; }
}
hh query(int type,int l,int r)
{
if (type) return suf[l]+pre[r];
if (id[l]==id[r]) return mx2[id[l]][l-L[id[l]]][r-L[id[l]]];
if (id[l]+1==id[r]) return suf[l]+pre[r];
return suf[l]+mx1[id[l]+1][id[r]-1]+pre[r];
}
void modify(int type,int p,hh w)
{
a[p]=w;
int i=id[p];
pre[L[i]]=a[L[i]],suf[R[i]]=a[R[i]];
rep(j,L[i]+1,R[i]) pre[j]=pre[j-1]+a[j];
drep(j,R[i]-1,L[i]) suf[j]=a[j]+suf[j+1];
if (type) return;
rep(j,L[i],R[i]){ hh cur=mx2[i][j-L[i]][j-L[i]]=a[j]; rep(k,j+1,R[i]) cur=cur+a[k],mx2[i][j-L[i]][k-L[i]]=cur; }
rep(j,1,cnt) { hh cur=mx1[j][j]=mx2[j][0][R[j]-L[j]]; rep(k,j+1,cnt) cur=cur+mx2[k][0][R[k]-L[k]],mx1[j][k]=cur; }
}
}s[S];
void init(hh *a,int n)
{
s[0].a.resize(n+1);
s[0].m=n;
rep(i,1,n) s[0].a[i]=a[i];
s[0].init(1);
rep(i,1,s[0].cnt)
{
s[i].a.resize(s[0].R[i]-s[0].L[i]+3);
rep(j,s[0].L[i],s[0].R[i]) s[i].a[j-s[0].L[i]+1]=a[j],++s[i].m;
}
rep(i,1,s[0].cnt) s[i].init(0);
int cnt=s[0].cnt;
s[cnt+1].a.resize(cnt+1);
rep(i,1,cnt) s[cnt+1].a[i]=s[0].pre[s[0].R[i]];
s[cnt+1].m=cnt;
s[cnt+1].init(0);
}
hh query(int l,int r)
{
int il=s[0].id[l],ir=s[0].id[r];
if (il==ir-1) return s[0].query(1,l,r);
if (il==ir) return s[il].query(0,l-s[0].L[il]+1,r-s[0].L[il]+1);
return s[0].suf[l]+s[s[0].cnt+1].query(0,il+1,ir-1)+s[0].pre[r];
}
void modify(int p,hh w)
{
s[0].modify(1,p,w);
int i=s[0].id[p];
s[i].modify(0,p-s[0].L[i]+1,w);
s[s[0].cnt+1].modify(0,i,s[0].pre[s[0].R[i]]);
}
};
int n,m;
int a[sz];
struct hhh
{
ll lmx,rmx,mx,sum;
hhh (ll Lmx=0,ll Rmx=0,ll Mx=0,ll Sum=0){lmx=Lmx,rmx=Rmx,mx=Mx,sum=Sum;}
const hhh operator + (const hhh &x) const
{
hhh ret;
ret.lmx=max(lmx,x.lmx+sum);
ret.rmx=max(x.rmx,rmx+x.sum);
ret.mx=max({mx,x.mx,rmx+x.lmx});
ret.sum=sum+x.sum;
return ret;
}
}A[sz];
MySqrtTree<hhh>tr;
int main()
{
file();
read(n);
rep(i,1,n) read(a[i]),A[i]=hhh(a[i],a[i],a[i],a[i]);
tr.init(A,n);
read(m);
int x,y,z;
while (m--)
{
read(z,x,y);
if (z==0) tr.modify(x,hhh(y,y,y,y));
else printf("%lld\n",tr.query(x,y).mx);
}
return 0;
}
(正经的学习笔记在路上了……)
SqrtTree学习笔记的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
随机推荐
- 2.7_Database Interface OLE-DB诞生
ODBC仅支持关系数据库,以及传统的数据库类型,并且只以C/C++语言API(API就是一些C语言的代码,是最底层的程序,在windows中就是一些.dll的文件)形式提供服务,因而无法符合日渐复杂的 ...
- java框架学习系列
这篇文章的目的主要是作为一个框架学习的索引,方便查找及顺序学习 一.struts2学习 1. java之struts框架入门教程 2. java之struts2的执行流程讲解 3. java之stru ...
- [jsp学习笔记] jsp基础知识 数据初始化、同步
- Flutter Image(图片)
Image是一个用于展示图片的组件.支持 JPEG.PNG.GIF.Animated GIF.WebP.Animated WebP.BMP 和 WBMP 等格式. Image 有许多的静态函数: ne ...
- 【转载】JVM结构、GC工作机制详解
文章主要分为以下四个部分 JVM结构.内存分配.垃圾回收算法.垃圾收集器.下面我们一一来看. 一.JVM结构 根据<java虚拟机规范>规定,JVM的基本结构一般如下图所示: 从左图可知, ...
- 平衡二叉树详解——PHP代码实现
一.什么是平衡二叉树 平衡二叉树(Self-Balancing Binary Search Tree 或者 Height-Balancing Binary Search Tree)译为 自平衡的二叉查 ...
- 【转载】C#中List集合使用Last方法获取最后一个元素
在C#的List集合操作过程中,如果要获取List集合中的最后一个元素对象,则一般会先通过获取到list集合的个数Count属性,然后再使用索引的方式获取到该集合的最后一个位置的元素信息.其实在Lis ...
- 将H5页面打包成安卓原生app
第一步:下载HBuilderX,新建项目选择5+App新建一个空项目如下图 新建后项目目录结构如下图 第二步,将你要打包成安卓app的文件打包,最后生成的文件目录如下图 1.打包完成后,将对应文件内容 ...
- angular异步获取数据后在ngOnInit中无法获取,显示undefined解决办法
两种方法 1 通过*ngif动态加载要数据渲染的dom 2 通过路由导航resolve 第一种感觉太麻烦了,要是一个页面请求多个接口,那就不得不写多个*ngif,本人还是更倾向与第二种发法 具体步骤: ...
- [转].net mvc + vuejs 的项目结构
.net项目结构: 程序目录结构: vue操作: 前提:安装npm ,vue,vue-cli 1.进入控制台窗口 2.进入程序目录 3.运行 vue init webpack webjs 生成webj ...