0%

「BZOJ 2639」 矩形计算

BZOJ 2639

题意

给出一个$n$行$m$列的矩阵,有$q$次询问,每次指定一个子矩阵,询问每种数字在这个子矩阵中出现次数的平方和

$n,m\le200,q\le10^5$


分析

把矩阵的$n$个行分成$\lfloor\sqrt{n}\rfloor$大小的块,$m$个列分成$\lfloor\sqrt{m}\rfloor$大小的块。

$n,m$同阶,共有$\mathcal O(n)$个块。

顺序遍历每个块,按照次序定义优先级(代码中是蛇形顺序)

把询问按照左上端点所在块的优先级为第一关键字,右下端点所在块的优先级为第二关键字排序。

开桶维护每个数字出现次数。

每次暴力转移即可

复杂度的一个上界是$\mathcal O(n^3\sqrt{n}+qn\sqrt{n})$


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<math.h>

using namespace std;
#define ll long long

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
return (s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin), (s == t ? -1 : *s++) : *s++);
}
template<class T>
inline void read(T &x) {
static bool iosig;
static char c;
for (iosig = false, c = read(); !isdigit(c); c = read()) {
if (c == '-') iosig = true;
if (c == -1) return;
}
for (x = 0; isdigit(c); c = read()) x = ((x + (x << 2)) << 1) + (c ^ '0');
if (iosig) x = -x;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *ooh = obuf;
inline void print(char c) {
if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh = obuf;
*ooh++ = c;
}
template<class T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) print('0');
else {
if (x < 0) print('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) print((char)buf[cnt--]);
}
}
inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }
const int N = 202, M = 40005, Q = 100005, K = 16;
int n, m, q, cnt, id, sn, sm, x, y, xx, yy, ans, b[K][K], a[N][N], rk[N][N], d[M], Ans[Q];
pair<int,int*> p[M];
struct query{
int x, y, xx, yy, id;
inline void input(){
read(x), read(y), read(xx), read(yy);
if(x>xx) swap(x, xx);
if(y>yy) swap(y, yy);
}
inline bool operator <(const query &rhs)const{ return rk[x][y]!=rk[rhs.x][rhs.y]?rk[x][y]<rk[rhs.x][rhs.y]:rk[xx][yy]<rk[rhs.xx][rhs.yy];}
} s[Q];
void insl(int x){ for(int i=y; i<=yy; ++i) ans+=2*d[a[x][i]]+++1;}
void dell(int x){ for(int i=y; i<=yy; ++i) ans-=2*d[a[x][i]]---1;}
void insc(int y){ for(int i=x; i<=xx; ++i) ans+=2*d[a[i][y]]+++1;}
void delc(int y){ for(int i=x; i<=xx; ++i) ans-=2*d[a[i][y]]---1;}
int main() {
read(n), read(m);
for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j)
read(a[i][j]), p[++cnt]=make_pair(a[i][j], &a[i][j]);
sort(p+1, p+cnt+1);
for(int i=1; i<=cnt; ++i) *(p[i].second)=(p[i].first==p[i-1].first?id:++id);
sn=sqrt(n), sm=sqrt(m), id=0;
for(int i=1; i<=(n-1)/sn+1; ++i){
if(i&1) for(int j=1; j<=(m-1)/sm+1; ++j) b[i][j]=++id;
else for(int j=(m-1)/sm+1; j; --j) b[i][j]=++id;
}
for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j)
rk[i][j]=b[(i-1)/sn+1][(j-1)/sm+1];
read(q);
for(int i=1; i<=q; ++i) s[i].input(), s[i].id=i;
sort(s+1, s+q+1);
x=1, y=1, xx=0, yy=0;
for(int i=1; i<=q; ++i){
while(x>s[i].x) insl(--x);
while(xx<s[i].xx) insl(++xx);
while(y>s[i].y) insc(--y);
while(yy<s[i].yy) insc(++yy);
while(x<s[i].x) dell(x++);
while(xx>s[i].xx) dell(xx--);
while(y<s[i].y) delc(y++);
while(yy>s[i].yy) delc(yy--);
Ans[s[i].id]=ans;
}
for(int i=1; i<=q; ++i) print(Ans[i]), print('\n');
return flush(), 0;
}