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