首页 > 其他分享 >猫树分治

猫树分治

时间:2024-02-26 20:11:43浏览次数:14  
标签:10 le int 分治 mid 猫树 ch define

就是说,对于分治区间 \([l,r]\),记 \(mid=\lfloor\dfrac{l+r}{2}\rfloor\),对于 \([l,mid]\) 和 \([mid+1,r]\) 内的询问继续递归,把跨越两边的询问用左右的信息合并处理。


P6240 好吃的题目

物品 \(i\) 有体积 \(w_i\) 和价值 \(c_i\),多次询问,对 \([l,r]\) 做 01 背包,问体积 \(\le t\) 的最大价值。

\(n\le 4\times 10^4\),\(m\le 2\times 10^5\),\(w_i,t\le 200\),\(c_i\le 10^7\)。


板。对于左边处理所有后缀的背包,右边处理前缀。

\(O(nV\log n+qV)\)。

record


GJ Round 2024.2.20

给定 \(n,m,\{a_n\}\),每次查询 \([l,r]\) 中和为 \(m\) 的倍数的子集数 \(\bmod {10^9+7}\)。

\(n,q\le 2\times 10^5\),\(m\le 20\)。


这是一样的。\(O(nm\log n+qm^2)\)。

点击查看代码
#include<bits/stdc++.h>
#define N 200010
#define M 20
#define P 1000000007
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
int n,m,p,a[N];
int L[N][M],R[N][M],ans[N];
struct Q{
	int l,r,id;
}q[N],b[N];
void solve(int l,int r,int ql,int qr){
	if(ql>qr)return;
	int mid=(l+r)>>1;
	memset(L[mid+1],0,sizeof(L[mid+1]));
	memset(R[mid],0,sizeof(R[mid]));
	L[mid+1][0]=1;
	for(int i=mid;i>=l;i--)
		for(int j=0,k;j<p;j++){
			k=(j+a[i])%p;
			L[i][k]=(L[i+1][j]+L[i+1][k])%P;
		}
	R[mid][0]=1;
	for(int i=mid+1;i<=r;i++)
		for(int j=0,k;j<p;j++){
			k=(j+a[i])%p;
			R[i][k]=(R[i-1][j]+R[i-1][k])%P;
		}
	int tl=ql,tr=qr;
	for(int i=ql;i<=qr;i++)b[i]=q[i];
	for(int i=ql;i<=qr;i++){
		if(b[i].r<mid)q[tl++]=b[i];
		else if(b[i].l>mid)q[tr--]=b[i];
		else{
			int cur=0;
			for(int j=0;j<p;j++)
				cur=(cur+1ll*L[b[i].l][j]*R[b[i].r][j?p-j:0])%P;
			ans[b[i].id]=cur;
		}
	}
	solve(l,mid,ql,tl-1),solve(mid+1,r,tr+1,qr);
}
int main(){
	n=read(),p=read();
	for(int i=1;i<=n;i++)a[i]=read()%p;
	m=read();
	for(int i=1,l,r;i<=m;i++){
		l=read(),r=read();
		q[i]={l,r,i};
	}
	solve(1,n,1,m);
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);

	return 0;
}

标签:10,le,int,分治,mid,猫树,ch,define
From: https://www.cnblogs.com/SError0819/p/18035081

相关文章

  • 猫树分治
    就是说,对于分治区间\([l,r]\),记\(mid=\lfloor\dfrac{l+r}{2}\rfloor\),对于\([l,mid]\)和\([mid+1,r]\)内的询问继续递归,把跨越两边的询问用左右的信息合并处理。P6240好吃的题目物品\(i\)有体积\(w_i\)和价值\(c_i\),多次询问,对\([l,r]\)做01背包,问体积\(\let......
  • 线段树分治&cdq分治&整体二分
    preface感觉三种分治算法容易搞混并不容易区分它们使用的场景和题目(虽然有些题目根据性质可以使用多种分治),所以还是要归纳一下线段树分治Part1主要是处理一类带有撤回的问题,也就是一次修改只对一段区间生效(这里的区间指的是时间)即区间修改,单点查询流程大致是把区间修改挂在......
  • #根号分治,分块,dfs序#洛谷 7710 [Ynoi2077] stdmxeypz
    题目传送门分析首先把距离变成深度,用dfs序转成区间问题,考虑分块,散块直接改问题是整块,如果模数比较大,可以以深度为第一维下标差分标记,这样查询时就可以前缀和知道答案如果模数比较小,那么给该块打标记,查询时枚举模数即可,然后块长取1000,模数阈值取300,就能尽量减少时间代码#in......
  • #根号分治,分块#洛谷 5309 [Ynoi2011] 初始化
    题目传送门分析如果\(x\)比较大那么可以暴力修改,\(x\)比较小的话可以用数组打标记查询的时候对于暴力修改的部分可以分块,暴力修改的同时需要给块打标记如果\(x\)比较小的情况,一段区间相当于是中间很多段周期加上前后缀(当然可以直接区间减但是我被卡常了)我调的块长是160......
  • 分治
    【引入】分(而)治(之)。把一个问题分解成规模更小的子问题,从而降低复杂度的算法。【归并排序】我们用选择排序,复杂度是\(O(\frac{n^2}{2})\)。但是如果我们把数组分成两半,分别选择排序,再归并起来,复杂度就降低为\(O(\frac{n^2}{4}+n)\),几乎快了一半。那么,如果我们一直不停分下......
  • 根号分治学习笔记
    根号分治根号分治其实一般是广义上的阈值分治,当范围不超过\(B\)时用一种方法,超过\(B\)时用另一种做法。之所以叫根号分治主要是大部分的应用都是在和一定时,不超过\(\sqrt{n}\)的可以把所有\(1\sim\sqrt{n}\)的都处理,超过\(\sqrt{n}\)的最多只有\(O(\sqrt{n})\)个,也......
  • 点分治学习笔记
    点分治点分治是一种处理树上路径问题的常见方法。先引入例题。求树上有多少条路径的长度是3的倍数。点分治的过程是每次找到当前联通块的重心,然后处理所有跨过重心的路径,然后删去重心,递归每个子树再进行处理。根据重心的性质,重心的每个儿子的子树大小都不超过\(\dfrac{n}{......
  • CDQ分治学习笔记
    CDQ分治其实CDQ本质就类似线段树,\(i\)的贡献由\(1\)到\(i-1\)在线段树上拆出的log个节点组成,然后将可以被同一段区间做贡献的点一起计算从而保证复杂度。例题:P3810【模板】三维偏序(陌上花开)题意:对于\(k\in[1,n]\)求三维偏序数量为\(k\)的点的个数。思路:其实就是求每个点的......
  • 树分治
    目录树分治点分治入门1P4178TreeProblemSolutionP4149[IOI2011]RaceProblemSolutionP6626[省选联考2020B卷]消息传递ProblemSolutionP5351RuriLovesMascheraProblemSolutionCF293ECloseVerticesProblemSolution点分治入门2P5306[COCI2018-2019#5]TransportProblemS......
  • 线段树分治学习笔记
    线段树分治线段树分治是一种可以离线处理带撤销问题的常用手段。一般而言,题目中加入操作很好维护,但删除操作不好维护,这时可以对时间维建线段树,把每一个操作加入其存在时间段对应的线段树节点上,然后处理所有询问,进入一个节点时将这个节点里的操作加入,递归左右儿子,然后撤销这一次做......