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];
}

  

posted @ 2020-05-13 21:05  我微笑不代表我快乐  阅读(170)  评论(0编辑  收藏  举报