猫树 学习笔记

参考资料

猫老师博客日报一篇题解


 

概述

猫树,一种支持快速查询区间信息的数据结构,可以维护各种满足结合律的信息,如区间和,区间最值,平均数等

可以在 $O(nlogn)$ 的预处理下 $O(1)$ 查询信息。在很多时候可以代替 ST表 或线段树等数据结构(但修改比较麻烦相当于重建

适用于一些不需要支持修改操作,且询问较多的题目。


 

实现

预处理:

我们把区间长度开到 $2^i$。为什么后面讲(

然后对于整个区间取 $mid$ 然后对于 $mid~1$ 倒序维护,对于 $mid+1~len(2^i)$ 进行正序遍历。时间复杂度 $O(n)$。

然后对左右区间继续分,继续处理。

查询

我们考虑对于区间 $[l,r]$,我们考虑如果 $[l,r]$ 不能同时被一个节点分成两段(不一定平分),

那么他们一定在一个节点左儿子或右儿子包含的区间内,向下迭代即可。

如果被分成两段,那么我们直接查询信息即可。

因为在这一层 $l$~$mid$ 的区间的信息都维护在了 $f_l$ 上,$mid+1$~$r$ 的区间的信息都维护在了 $f_r$ 上,所以直接合并即可。

很容易发现这个点就是两个节点在这棵猫树上的 $LCA$!

那么现在的问题就转化为求两点 $LCA$ 所在层。(因为我们将同一层的信息维护到同一维数组里)

但我们查询效率是 $O(1)$ 的,所以我们考虑从树的结构下功夫。

我们把数组开到了$2^i$ 就是为了现在!我们很容易发现在堆式结构存储的猫树上两点 $LCA$ 即为两点的 $LCP$(最长公共前缀)!(大家可以手模一下。

所以我们把两个数异或起来求 $log$ 再求原来点的 $log$,相减即为深度。

以ST表模板题为例:

复制代码
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5  
 6 using namespace std;
 7 
 8 static char buf[100000],*pa=buf,*pd=buf;
 9 #define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
10 inline int read()
11 {
12     register int x(0);register char c(gc);
13     while(c<'0'||c>'9')c=gc;
14     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
15     return x;
16 }
17 void print(int x){
18     if(x<0) {putchar('-');x=-x;}
19     if(x>9) print(x/10);
20     putchar(x%10+'0');
21 }
22 
23 const int N=1e5+5;
24 int n,m,a[N<<1],l,r;
25 int len=1,f[N<<1][25],t[N<<1],lg[N<<2];
26 
27 void build(int node,int l,int r,int dep){
28     if(l==r){
29         t[r]=node;
30         return ;
31     }
32     int mid=(l+r)>>1;
33     build(node<<1,l,mid,dep+1);
34     build(node<<1|1,mid+1,r,dep+1);
35     f[mid][dep]=a[mid];
36     for(int i=mid-1;i>=l;i--)
37         f[i][dep]=max(f[i+1][dep],a[i]);
38     f[mid+1][dep]=a[mid+1];
39     for(int i=mid+2;i<=r;i++)
40         f[i][dep]=max(f[i-1][dep],a[i]);
41 }
42 
43 int main(){
44     n=read();m=read();
45     for(int i=1;i<=n;i++) a[i]=read();
46     while(len<n) len*=2;
47     build(1,1,len,1);
48     lg[0]=1;lg[1]=1;
49     for(int i=2;i<=len*2;i++) lg[i]=lg[i/2]+1;
50     while(m--){
51         l=read(),r=read();
52         if(l==r) print(a[r]);
53         else{
54             int k=lg[t[r]]-lg[t[l]^t[r]];
55              print(max(f[l][k],f[r][k]));
56         }
57         printf("\n");
58     }
59     return 0;
60 }
复制代码

需要注意的是,猫树不支持修改(会T飞

不想写ST表的时候可以写一写(

慎用!(不过考场基本用不上 

posted @   々Trouvaille々  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
点击右上角即可分享
微信分享提示