ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

猫树分治小记

2021-09-12 21:02:11  阅读:264  来源: 互联网

标签:log int text 复杂度 分治 mid 猫树 mathcal 小记


一个非常 trivial 也不太常见的算法,不过学过了就不要忘了哦(

猫树问题可以适用于离线解决以下类型的数据结构问题:

  • 与序列有关,且询问是一段区间
  • 序列静态,即,不涉及修改操作

当然离不离线都可以,由于其过程类似于点分治,所以在线的情况可通过类似于建出建出点分治的情况动态维护。

首先我们总结一下,序列有关的静态区间询问问题有什么一般性的解决方法(注:下文中默认 \(n\) 为序列长度,\(q\) 为询问次数):

  • 如果贡献支持相减,如和/异或和,那么一遍前缀和即可搞定,时间复杂度 \(n+q\)​

  • 如果贡献不支持相减,但允许重复计算,如 \(\min,\max,\text{or},\text{and}\)​,那么有以下三种选择:

    • 线段树维护区间答案,\(\mathcal O(n+q\log n)\),缺点是回答询问复杂度多一个 \(\log\)。

    • ST 表预处理 + \(\mathcal O(1)\) 回答询问,\(\mathcal O(n\log n+q)\),缺点是空间太大。

    • 建出笛卡尔树 + \(\mathcal O(n)-\mathcal O(1)\) LCA,\(\mathcal O(n+q)\),缺点是 \(\mathcal O(n)-\mathcal O(1)\) LCA 普及率太低,没啥实用性

  • 如果贡献不能重复运算也不支持相减,但支持合并,那么只能线段树维护区间答案,\(\mathcal O(n+q\log n)\)

当然以上复杂度分析都是建立在合并两个答案的复杂度为 \(\mathcal O(1)\) 的基础上的,那么如果合并两个答案的复杂度不是 \(\mathcal O(1)\) 怎么办呢?如果我们记合并的复杂度为 \(T_{\text{merge}}(n)\),那么在上面的算法中,使用线段树维护区间的真实复杂度应是 \(n·T_{\text{merge}}(n)+q\log n·T_{\text{merge}}(n)\),使用 ST 表维护区间的真实复杂度应是 \(n\log n·T_{\text{merge}}(n)+q·T_{\text{merge}}(n)\)。如果 \(T_{\text{merge}}(n)\) 级别较高那我们的做法就不太适用了,那么有什么简便点的办法呢?这时候就要用到猫树分治了。

猫树分治的大致思想有点像整体二分,又有点像分治求满足 xxx 条件的区间个数的思想(如果不太明白怎样分治数区间可以见我 P5502 的题解,看我自己想出来的那个方法,或者 CF1175F 的题解中那个分治的解法,应该不至于看不明白罢,不会吧不会吧)。考虑分治区间 \([l,r]\) 时候将所有满足 \([L,R]\subseteqq [l,r]\) 的区间压入一个 vector。如果 \(l=r\) 那答案一般是比较好求的,直接算就行了。否则设 \(mid=\lfloor\dfrac{l+r}{2}\rfloor\),然后对于 \(i\in[l,mid]\) 扫一遍处理 \([i,mid]\) 的答案,再对于 \(i\in[mid+1,r]\) 也扫一遍处理 \([mid+1,i]\) 的答案,这样处理某个询问 \([L,R]\) 时:

  • 如果 \([L,R]\subseteqq[l,mid]\) 则把它放到左边区间的 vector 里递归
  • 如果 \([L,R]\subseteqq[mid+1,r]\)​ 则把它放到左边区间的 vector 里递归
  • 如果 \(L\in[l,mid],R\in[mid+1,r]\),则将 \([L,mid],[mid+1,R]\) 的答案合并即可。

不难发现,在上述做法中,我们通过分治把 \(\log\) 的复杂度和单次插入的复杂度摊到了一起,这样每次询问时只用合并一次。如果我们记插入的复杂度为 \(T_{\text{insert}}(n)\),那么上述算法的复杂度就是 \(n\log n·T_{\text{insert}}(n)+q·T_{\text{merge}}(n)\)。

当然如果强制在线也做得了,直接对于每一层分治记录下 \([i,mid],[mid+1,j]\) 的答案,这样可以做到强制在线,复杂度 \(n\log n·T_{\text{insert}}(n)+q\log n+q·T_{\text{merge}}(n)\),当然这样空间可能略有点危,如果记我们单个合并的信息的空间复杂度为 \(M(n)\),那么该做法空间复杂度为 \(n\log n·M(n)\)。

接下来看一些例子吧:

1. P6240 好吃的题目

模板题,上述过程中的结构换成背包即可,这样往背包中加入一个元素复杂度为 \(\mathcal O(V)\),合并两个背包复杂度也是 \(\mathcal O(V)\),总复杂度就是 \(n\log n·V+qV\)​,可以通过此题。

放个代码吧:

const int MAXN=4e4;
const int MAXQ=2e5;
const int MAXV=200;
int n,qu,h[MAXN+5],w[MAXN+5],res[MAXQ+5];
struct qry{int l,r,t;} q[MAXQ+5];
int pre[MAXN+5][MAXV+5],suf[MAXN+5][MAXV+5];
void solve(int l,int r,vector<int> cd){
	if(l==r){
		for(int id:cd) res[id]=(h[l]<=q[id].t)?w[l]:0;
		return;
	} int mid=l+r>>1;vector<int> nL,nR;
	for(int i=l;i<=r;i++) for(int j=0;j<=MAXV;j++)
		pre[i][j]=suf[i][j]=0;
	for(int i=mid;i>=l;i--){
		for(int j=0;j<=MAXV;j++) suf[i][j]=suf[i+1][j];
		for(int j=h[i];j<=MAXV;j++) chkmax(suf[i][j],suf[i+1][j-h[i]]+w[i]);
	}
	for(int i=mid+1;i<=r;i++){
		for(int j=0;j<=MAXV;j++) pre[i][j]=pre[i-1][j];
		for(int j=h[i];j<=MAXV;j++) chkmax(pre[i][j],pre[i-1][j-h[i]]+w[i]);
	}
	for(int id:cd){
		if(q[id].r<=mid) nL.pb(id);
		else if(q[id].l>mid) nR.pb(id);
		else{
			for(int i=0;i<=q[id].t;i++)
				chkmax(res[id],suf[q[id].l][i]+pre[q[id].r][q[id].t-i]);
		}
	} solve(l,mid,nL);solve(mid+1,r,nR);
}
int main(){
	scanf("%d%d",&n,&qu);vector<int> ini;
	for(int i=1;i<=n;i++) scanf("%d",&h[i]);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	for(int i=1;i<=qu;i++) scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].t),ini.pb(i);
	solve(1,n,ini);
	for(int i=1;i<=qu;i++) printf("%d\n",res[i]);
	return 0;
}

2. CF1100F Ivan and Burgers

Yet another mol ban tea,把上文中的结构替换成线性基即可,仿照上一题的复杂度分析可知该做法复杂度是 \((n+q)\log^2n\) 的,劣于第一次做这道题时使用的前缀线性基做法,不过还是可以通过此题。

参考文献:

标签:log,int,text,复杂度,分治,mid,猫树,mathcal,小记
来源: https://www.cnblogs.com/ET2006/p/msfz.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有