<法一>二维莫队,对n和m分别分块后,对块从上到下从左到右依次编号,询问以左上角所在块编号为第一关键字,以右下角标号为第二关键字排序,转移时非常厉害。

O(q*n*sqrt(n))。

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 201
#define M 100001
struct LiSan{int p,v;}t[N*N];
bool operator < (const LiSan &a,const LiSan &b){return a.v<b.v;}
int n,m,nm,zy,a[N][N],b[N*N],num[N][N],id[N][N];
struct ASK{int x1,y1,x2,y2,p;}Q[M];
bool operator < (const ASK &a,const ASK &b)
{return num[a.x1][a.y1]!=num[b.x1][b.y1] ?
num[a.x1][a.y1]<num[b.x1][b.y1] :
id[a.x2][a.y2]<id[b.x2][b.y2];}
void lisan()
{
scanf("%d%d",&n,&m); nm=n*m;
for(int i=1;i<=nm;++i)
{
scanf("%d",&t[i].v);
t[i].p=i;
}
sort(t+1,t+nm+1);
b[t[1].p]=++zy;
for(int i=2;i<=nm;++i)
{
if(t[i].v!=t[i-1].v) ++zy;
b[t[i].p]=zy;
}
int pen=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=b[++pen];
}
void makeblock()
{
int sun=sqrt(n),sum=sqrt(m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
num[i][j]=(i-1)/sun*sum+(j-1)/sum+1;
}
int ans,T[N*N];
bool vis[N][N];
inline void Insert(const int &x,const int &y)
{
if(!vis[x][y])
{
vis[x][y]=1;
ans+=((T[a[x][y]]++)<<1|1);
}
}
inline void Delete(const int &x,const int &y)
{
if(vis[x][y])
{
vis[x][y]=0;
ans-=((--T[a[x][y]])<<1|1);
}
}
inline void trans(const ASK &a,const ASK &b)
{
int t=min(a.x1-1,b.x2);
for(int i=b.x1;i<=t;++i)
for(int j=b.y1;j<=b.y2;++j)
Insert(i,j);
for(int i=max(b.x1,a.x2+1);i<=b.x2;++i)
for(int j=b.y1;j<=b.y2;++j)
Insert(i,j);
t=min(a.y1-1,b.y2);
for(int j=b.y1;j<=t;++j)
for(int i=b.x1;i<=b.x2;++i)
Insert(i,j);
for(int j=max(b.y1,a.y2+1);j<=b.y2;++j)
for(int i=b.x1;i<=b.x2;++i)
Insert(i,j);
t=min(b.x1-1,a.x2);
for(int i=a.x1;i<=t;++i)
for(int j=a.y1;j<=a.y2;++j)
Delete(i,j);
for(int i=max(a.x1,b.x2+1);i<=a.x2;++i)
for(int j=a.y1;j<=a.y2;++j)
Delete(i,j);
t=min(b.y1-1,a.y2);
for(int j=a.y1;j<=t;++j)
for(int i=a.x1;i<=a.x2;++i)
Delete(i,j);
for(int j=max(a.y1,b.y2+1);j<=a.y2;++j)
for(int i=a.x1;i<=a.x2;++i)
Delete(i,j);
}
int q,anss[M];
int main()
{
// freopen("bzoj2639.in","r",stdin);
// freopen("bzoj2639.out","w",stdout);
lisan();
makeblock();
int pen=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
id[i][j]=++pen;
scanf("%d", &q);
for(int i=1;i<=q;++i)
{
scanf("%d%d%d%d",&Q[i].x1,&Q[i].y1,&Q[i].x2,&Q[i].y2);
if(Q[i].x1>Q[i].x2) swap(Q[i].x1,Q[i].x2);
if(Q[i].y1>Q[i].y2) swap(Q[i].y1,Q[i].y2);
Q[i].p=i;
}
sort(Q+1,Q+1+q);
for(int i=Q[1].x1;i<=Q[1].x2;++i)
for(int j=Q[1].y1;j<=Q[1].y2;++j)
Insert(i,j);
anss[Q[1].p]=ans;
for(int i=2;i<=q;++i)
{
trans(Q[i-1],Q[i]);
anss[Q[i].p]=ans;
}
for(int i=1;i<=q;++i)
printf("%d\n",anss[i]);
return 0;
}

<法二>二维分块,分块在矩阵中的扩展,预处理前缀矩阵每个数出现的次数,以及所有“子矩块”的答案。询问的时候整块的部分直接获取,零散的部分暴力转移。TLE。

复杂度O(n^2+q)*n*sqrt(n),常数较大。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int f,C;
inline void R(int &x){
C=0;f=1;
for(;C<'0'||C>'9';C=getchar())if(C=='-')f=-1;
for(x=0;C>='0'&&C<='9';C=getchar())(x*=10)+=(C-'0');
x*=f;
}
inline void P(int x){
if(x<10)putchar(x+'0');
else{P(x/10);putchar(x%10+'0');}
}
#define N 202
#define BN 17
int n,m,nm;
struct Point{int x,y;}num[N][N];
inline bool operator == (const Point &a,const Point &b){return a.x==b.x && a.y==b.y;}
struct LiSan{int p,v;}t[N*N];
inline bool operator < (const LiSan &a,const LiSan &b){return a.v<b.v;}
int b[N*N],a[N][N],zy,szn,szm,ln[BN],rn[BN],lm[BN],rm[BN],sun=1,sum=1;
void makeblock()
{
szn=sqrt(n);
for(;sun*szn<n;++sun)
{
ln[sun]=rn[sun-1]+1;
rn[sun]=sun*szn;
}
ln[sun]=rn[sun-1]+1;
rn[sun]=n;
//
szm=sqrt(m);
for(;sum*szm<m;++sum)
{
lm[sum]=rm[sum-1]+1;
rm[sum]=sum*szm;
}
lm[sum]=rm[sum-1]+1;
rm[sum]=m;
//
for(int i=1;i<=sun;++i)
for(int j=1;j<=sum;++j)
for(int k=ln[i];k<=rn[i];++k)
for(int l=lm[j];l<=rm[j];++l)
num[k][l]=(Point){i,j};
}
int anss[BN][BN][BN][BN];
int T[N*N];
int sumv[BN][BN][N*N];
int haha[BN],hehe[BN];
void Init_Sumv()
{
for(int i=1;i<=sun;++i)
for(int j=1;j<=sum;++j)
{
memcpy(sumv[i][j]+1,sumv[i][j-1]+1,sizeof(int)*zy);
for(int k=ln[i];k<=rn[i];++k)
for(int l=lm[j];l<=rm[j];++l)
++sumv[i][j][a[k][l]];
}
for(int j=1;j<=sum;++j)
for(int i=1;i<=sun;++i)
for(int k=1;k<=zy;++k)
sumv[i][j][k]+=sumv[i-1][j][k];
}
inline int Calc(int X1,int Y1,int X2,int Y2,int v)
{
if(!(X2>=X1 && Y2>=Y1)) return 0;
// int a[20][20];
static int* b=&sumv[0][0][0];
int *x=b+haha[X2]+hehe[Y2]+v;
int *y=b+haha[X1-1]+hehe[Y2]+v;
int *z=b+haha[X2]+hehe[Y1-1]+v;
int *l=b+haha[X1-1]+hehe[Y1-1]+v;
// if(*z!=sumv[X2][Y1-1][v])puts("jhsdhe");
// if(*(sumv+x))!=sumv[X2][Y2][v])puts("BaoJingLa");
return *x-*y-*z+*l;
}
void Init_Ans()
{
for(int i=1;i<=sun;++i)
for(int j=1;j<=sum;++j)
for(int k=i;k<=sun;++k)
for(int l=j;l<=sum;++l)
{
anss[i][j][k][l]=anss[i][j][k-1][l];
for(int o=j;o<=l;++o)
for(int p=ln[k];p<=rn[k];++p)
for(int q=lm[o];q<=rm[o];++q)
{
anss[i][j][k][l]+=((Calc(i,j,k-1,l,a[p][q])+T[a[p][q]])<<1|1);
++T[a[p][q]];
}
for(int o=j;o<=l;++o)
for(int p=ln[k];p<=rn[k];++p)
for(int q=lm[o];q<=rm[o];++q)
--T[a[p][q]];
}
}
int q;
int main()
{
// freopen("bzoj2639.in","r",stdin);
// freopen("bzoj2639.out","w",stdout);
R(n); R(m); nm=n*m;
for(int i(1);i<BN;i++) haha[i]=haha[i-1]+BN*N*N;
for(int i(1);i<BN;i++) hehe[i]=hehe[i-1]+N*N;
for(int i=1;i<=nm;++i)
{
R(t[i].v);
t[i].p=i;
}
sort(t+1,t+nm+1);
b[t[1].p]=++zy;
for(int i=2;i<=nm;++i)
{
if(t[i].v!=t[i-1].v) ++zy;
b[t[i].p]=zy;
}
int pen=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=b[++pen];
makeblock();
Init_Sumv();
Init_Ans();
int X1,Y1,X2,Y2;
R(q);
for(;q;--q)
{
R(X1); R(Y1); R(X2); R(Y2);
if(X1>X2)
swap(X1,X2);
if(Y1>Y2)
swap(Y1,Y2);
Point zs=(Point){num[X1][Y1].x+(num[X1][Y1]==num[X1-1][Y1]),
num[X1][Y1].y+(num[X1][Y1]==num[X1][Y1-1])};
Point yx=(Point){num[X2][Y2].x-(num[X2][Y2]==num[X2+1][Y2]),
num[X2][Y2].y-(num[X2][Y2]==num[X2][Y2+1])};
int ans=0;
if(!(yx.x>=zs.x && yx.y>=zs.y))
{
for(int i=X1;i<=X2;++i)
for(int j=Y1;j<=Y2;++j)
{
ans+=((T[a[i][j]])<<1|1);
++T[a[i][j]];
}
for(int i=X1;i<=X2;++i)
for(int j=Y1;j<=Y2;++j)
--T[a[i][j]];
}
else
{
ans=anss[zs.x][zs.y][yx.x][yx.y];
int TX=ln[zs.x]-1;
int TY=rm[yx.y];
for(int i=X1;i<=TX;++i)
for(int j=Y1;j<=TY;++j)
{
ans+=((T[a[i][j]]+Calc(zs.x,zs.y,yx.x,yx.y,a[i][j]))<<1|1);
++T[a[i][j]];
}
int TX2=rn[yx.x];
int TY2=rm[yx.y]+1;
for(int i=X1;i<=TX2;++i)
for(int j=TY2;j<=Y2;++j)
{
ans+=((T[a[i][j]]+Calc(zs.x,zs.y,yx.x,yx.y,a[i][j]))<<1|1);
++T[a[i][j]];
}
int TX3=rn[yx.x]+1;
int TY3=lm[zs.y];
for(int i=TX3;i<=X2;++i)
for(int j=TY3;j<=Y2;++j)
{
ans+=((T[a[i][j]]+Calc(zs.x,zs.y,yx.x,yx.y,a[i][j]))<<1|1);
++T[a[i][j]];
}
int TX4=ln[zs.x];
int TY4=lm[zs.y]-1;
for(int i=TX4;i<=X2;++i)
for(int j=Y1;j<=TY4;++j)
{
ans+=((T[a[i][j]]+Calc(zs.x,zs.y,yx.x,yx.y,a[i][j]))<<1|1);
++T[a[i][j]];
}
for(int i=X1;i<=TX;++i)
for(int j=Y1;j<=TY;++j)
--T[a[i][j]];
for(int i=X1;i<=TX2;++i)
for(int j=TY2;j<=Y2;++j)
--T[a[i][j]];
for(int i=TX3;i<=X2;++i)
for(int j=TY3;j<=Y2;++j)
--T[a[i][j]];
for(int i=TX4;i<=X2;++i)
for(int j=Y1;j<=TY4;++j)
--T[a[i][j]];
}
P(ans),puts("");
}
return 0;
}

【二维莫队】【二维分块】bzoj2639 矩形计算的更多相关文章

  1. BZOJ.2639.矩形计算(二维莫队)

    题目链接 二维莫队,按x,y坐标一起分块.(x,y)的所属的块为 x/sq(n)*sq(m) + y/sq(m) 排序时按照(左下点所在块,右上点的标号)排序 排序后 先得出一个询问的答案,然后利用上 ...

  2. [CSP-S模拟测试]:蔬菜(二维莫队)

    题目描述 小$C$在家中开垦了一块菜地,可以抽象成一个$r\times c$大小的矩形区域,菜地的每个位置都种着一种蔬菜.秋天到了,小$C$家的菜地丰收了. 小$C$拟定了$q$种采摘蔬菜的计划,计划 ...

  3. csp-s模拟测试50(9.22)「施工(单调栈优化DP)」·「蔬菜(二维莫队???)」·「联盟(树上直径)」

    改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调 ...

  4. 洛谷 P4887 -【模板】莫队二次离线(第十四分块(前体))(莫队二次离线)

    题面传送门 莫队二次离线 mol ban tea,大概是这道题让我第一次听说有这东西? 首先看到这类数数对的问题可以考虑莫队,记 \(S\) 为二进制下有 \(k\) 个 \(1\) 的数集,我们实时 ...

  5. luogu P4887 莫队二次离线

    珂朵莉给了你一个序列$a$,每次查询给一个区间$[l,r]$ 查询$l≤i<j≤r$,且$ai⊕aj$的二进制表示下有$k$个$1$的二元组$(i,j)$的个数.$⊕$是指按位异或. 直接暴力莫 ...

  6. luogu P4887 模板 莫队二次离线 莫队 离线

    LINK:模板莫队二次离线 很早以前学的知识点 不过 很久了忘了. 考虑暴力 :每次莫队更新的时候 尝试更新一个点到一个区间的答案 可以枚举二进制下位数为k的数字 看一下区间内的这种数字有多少个. 不 ...

  7. [BZOJ2639]矩形计算

    [BZOJ2639]矩形计算 题目大意: 给定一个\(n\times m(n,m\le200)\)的矩阵.\(q(q\le10^5)\)次询问,每次询问一个子矩阵中所有数字出现次数的平方和. 思路: ...

  8. 2019.01.08 bzoj3809: Gty的二逼妹子序列(莫队+权值分块)

    传送门 题意:多组询问,问区间[l,r]中权值在[a,b]间的数的种类数. 看了一眼大家应该都知道要莫队了吧. 然后很容易想到用树状数组优化修改和查询做到O(mnlogamax)O(m\sqrt nl ...

  9. BZOJ 4241: 历史研究——莫队 二叉堆

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4241 题意:N个int范围内的数,M次询问一个区间最大的(数字*出现次数)(加权众数),可以 ...

随机推荐

  1. JavaScript词法作用域与调用对象

    关于 Javascript 的函数作用域.调用对象和闭包之间的关系很微妙,关于它们的文章已经有很多,但不知道为什么很多新手都难以理解.我就尝试用比较通俗的语言来表达我自己的理解吧. 作用域 Scope ...

  2. POJ2594:Treasure Exploration(Floyd + 最小路径覆盖)

    Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 9794   Accepted: 3 ...

  3. java程序在centos7里面开机自启动

    1.我们先来个简单的start,status,stop程序: [root@localhost ~]# cat /home/tomcat/jarservice.sh #!/bin/bashCU_PID= ...

  4. 关于控制下拉框select只读的js控制

    文本框有readonly属性,直接设置:下拉框没有readonly属性,也不能通过其他属性进行只读的设置,下拉框只有disabled属性,但是这个属性设成true之后,值就获取不到了: 我在网上搜了一 ...

  5. jspersonft有关Table数据绑定(一)

    一:前言 在公司来就学着做报表,觉得这个报表学着还是很有意义的.jspersonft我在网上搜了一些有关的资料但是不是很多,现在就是学一点就记载一点.好记性不如烂笔头嘛! 二:在jspersonft定 ...

  6. 【SPOJ-QTREE3】树链剖分

    http://www.spoj.com/problems/QTREE3/ 时间限制:2s    代码长度限制:50000B     内存限制:1536MB [题目描述] 给出N个点的一棵树(N-1条边 ...

  7. 美团网技术团队分享的MySQL索引及慢查询优化教程

    MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓“好马配好鞍”,如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位 ...

  8. [Leetcode Week7]Jump Game

    Jump Game 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/jump-game/description/ Description Given a ...

  9. shell脚本(傻瓜式处理文件到指定分类)

    前言 每一到两周,我大概会新增十多个甚至更多的资料文件,都是些最近遇到的一些问题的总结或者相关技术文档,但是资料都是在公司电脑上,拷贝到自己电脑上后,又得一个个去找一个这个应该放到哪个分类,个人感觉很 ...

  10. 僵尸进程(zombie process)

    僵尸进程(zombie process) http://blog.csdn.net/crfoxzl/article/details/2124718 杀死Linux中的defunct进程(僵尸进程)的方 ...