bzoj2639 矩形计算
https://www.cnblogs.com/ouuan/p/2DMoDui.html
输入一个n*m的矩阵,矩阵的每一个元素都是一个整数,然后有q个询问,每次询问一个子矩阵的权值。矩阵的权值是这样定义的,对于一个整数x,如果它在该矩阵中出现了p次,那么它给该矩阵的权值就贡献p2。
Input
第一行两个整数n,m表示矩阵的规模。
接下来n行每行m个整数,表示这个矩阵的每个元素。
再下来一行一个整数q,表示询问个数。
接下来q行每行四个正整数x1,y1,x2,y2,询问以第x1行第y1列和第x2行第y2列的连线为对角线的子矩阵的权值。
Output
输出q行每行一个整数回答对应询问。
Sample Input
3 4
1 3 2 1
1 3 2 4
1 2 3 4
8
1 2 2 1
1 1 2 1
1 1 3 4
1 1 1 1
2 2 3 3
3 4 2 2
1 3 3 1
2 4 3 4
Sample Output
8
4
38
1
8
12
27
4
HINT
对于全部数据
1<=n,m<=200
q<=100000
|矩阵元素大小|<=2*10^9
Sol:
二维莫队
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int N=210; const int M=100010; void add(int x); void del(int x); int r,c,m,B,a[N][N],lsh[N*N],tot,cnt[N*N],ans,out[M]; struct Query { int x,y,xx,yy,id; bool operator<(Query& b) { return x/B==b.x/B?(y/B==b.y/B?(xx/B==b.xx/B?yy<b.yy:xx<b.xx):y<b.y):x<b.x; } } q[M]; int main() { int i,j,x=1,y=1,xx=0,yy=0; cin>>r>>c>>m; B=pow(r*c,0.5)/pow(m,0.25)+1.0; for (i=1;i<=r;++i) { for (j=1;j<=c;++j) { cin>>a[i][j]; lsh[tot++]=a[i][j]; //这题要离散化 } } sort(lsh,lsh+tot); tot=unique(lsh,lsh+tot)-lsh; for (i=1;i<=r;++i) { for (j=1;j<=c;++j) { a[i][j]=lower_bound(lsh,lsh+tot,a[i][j])-lsh; } } for (i=0;i<m;++i) { cin>>q[i].x>>q[i].y>>q[i].xx>>q[i].yy; q[i].id=i; } sort(q,q+m); for (i=0;i<m;++i) { while (x>q[i].x) { --x; for (j=y;j<=yy;++j) { add(a[x][j]); } } while (xx<q[i].xx) { ++xx; for (j=y;j<=yy;++j) { add(a[xx][j]); } } while (y>q[i].y) { --y; for (j=x;j<=xx;++j) { add(a[j][y]); } } while (yy<q[i].yy) { ++yy; for (j=x;j<=xx;++j) { add(a[j][yy]); } } while (x<q[i].x) { for (j=y;j<=yy;++j) { del(a[x][j]); } ++x; } while (xx>q[i].xx) { for (j=y;j<=yy;++j) { del(a[xx][j]); } --xx; } while (y<q[i].y) { for (j=x;j<=xx;++j) { del(a[j][y]); } ++y; } while (yy>q[i].yy) { for (j=x;j<=xx;++j) { del(a[j][yy]); } --yy; } out[q[i].id]=ans; } for (i=0;i<m;++i) { cout<<out[i]<<endl; } return 0; } void add(int x) { ans=ans+2*cnt[x]+1; ++cnt[x]; } void del(int x) { ans=ans-2*cnt[x]+1; --cnt[x]; }