高维莫队

本文深入探讨了针对高维数据结构的优化算法——四维莫队算法,详细阐述了如何通过合理划分和排序策略来降低算法的时间复杂度。以BZOJ2639矩形计算为例,介绍了算法的具体实现过程,包括数据预处理、块大小选择、询问排序及单次修改操作的优化技巧。

对于n维的询问,
将前n-1维值域按S的大小分块
最后1维按1的大小分块,
排序时,比较两个询问,
从小到大,一维一维的,
块编号小的放前,块编号大的放后,
相等就看下一维。
时间消耗是:
(n−1)qS+LnSn−1(n-1)qS + \frac{L^{n}}{S^{n-1}}(n1)qS+Sn1Ln (L代表询问值域)
S=(Ln(n−1)q)1nS =( \frac {L^{n}}{(n-1)q})^{\frac 1n}S=((n1)qLn)n1时取到最小,
复杂度为L((n−1)q)n−1nL((n-1)q)^{\frac {n-1}n}L((n1)q)nn1

举例子:
BZOJ 2639: 矩形计算
L <= 200 , n=4,q=100000
4维莫队,单次修改时间最大为O(L)
求出S = 8 时最小。。。
但是实际S=6表现最好。。。

时间复杂度6亿都能过 , 莫队真好玩

AC Code:

#include<bits/stdc++.h>
#define maxn 205
#define maxm 100005
using namespace std;

int n,m,q,a[maxn][maxn],b[maxn*maxn],cnt[maxn*maxn],ANS[maxm],c[maxm],ans;
int A[maxm],B[maxm],C[maxm],D[maxm],lba[maxm],lbb[maxm],lbc[maxm];
inline bool cmp(const int &u,const int &v)
{ return lba[u]==lba[v]?lbb[u]==lbb[v]?lbc[u]==lbc[v]?D[u]<D[v]:lbc[u]<lbc[v]:lbb[u]<lbb[v]:lba[u]<lba[v]; }
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &res)
{ 
	char ch;bool flag=0;
	for(;!isdigit(ch=getc());)if(ch=='-')flag=1;
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); 
	(flag) && (res=-res);
}

int main()
{
	read(n),read(m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) 
			read(a[i][j]),b[++b[0]] = a[i][j];
	sort(b+1,b+1+b[0]);
	b[0] = unique(b+1,b+1+b[0]) - b - 1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) 
			a[i][j] = lower_bound(b+1,b+1+b[0],a[i][j]) - b;
		
	read(q);
	int S = 6;
	for(int i=1;i<=q;i++)
	{
		read(A[i]),read(B[i]),read(C[i]),read(D[i]);
		(A[i] > C[i]) && (swap(A[i],C[i]),0);
		(B[i] > D[i]) && (swap(B[i],D[i]),0);
		lba[i]=A[i]/S,lbb[i]=B[i]/S,lbc[i]=C[i]/S,c[i]=i;
	}
	sort(c+1,c+1+q,cmp);
	int x=1,y=1,u=1,v=1;
	ans = 1 , cnt[a[1][1]]++;
	for(int i=1,p;i<=q;i++)
	{
		p=c[i];
		for(;x>A[p];)
		{
			x--;
			for(int j=y;j<=v;j++) ans += 2 * cnt[a[x][j]]+++1;
		}
		for(;u<C[p];)
		{
			u++;
			for(int j=y;j<=v;j++) ans += 2 * cnt[a[u][j]]+++1;
		}
		for(;y>B[p];) 
		{
			y--;
			for(int j=x;j<=u;j++) ans += 2 * cnt[a[j][y]]+++1;
		}
		for(;v<D[p];)
		{
			v++;
			for(int j=x;j<=u;j++) ans += 2 * cnt[a[j][v]]+++1;
		}
		
		for(;x<A[p];)
		{
			for(int j=y;j<=v;j++) ans -= 2 * cnt[a[x][j]]---1;
			x++;
		}
		for(;u>C[p];)
		{
			for(int j=y;j<=v;j++) ans -= 2 * cnt[a[u][j]]---1;
			u--;
		}
		for(;y<B[p];) 
		{
			for(int j=x;j<=u;j++) ans -= 2 * cnt[a[j][y]]---1;
			y++;
		}
		for(;v>D[p];)
		{
			for(int j=x;j<=u;j++) ans -= 2 * cnt[a[j][v]]---1;
			v--;
		}
		ANS[p] = ans;
	}
	for(int i=1;i<=q;i++)
		printf("%d\n",ANS[i]);
}**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值