[CSP-S模拟测试]:Rectangle(模拟+树状数组)

Posted wzc521

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP-S模拟测试]:Rectangle(模拟+树状数组)相关的知识,希望对你有一定的参考价值。

题目描述

平面上有$n$个点,第$i$个点的坐标为$X_i,Y_i$。对于其中的一个非空点集$S$,定义$f(S)$为一个最小矩形,满足:
$\\bullet$覆盖$S$中所有的点(在边界上也算覆盖);
$\\bullet$边与坐标轴平行。
求所有不同的$f(S)$的面积和对$10^9+7$取模的结果。两个矩形被认为是不同的,当且仅当它们顶点坐标不同。


输入格式

从文件$rectangle.in$中读入数据。
第一行一个整数$n$。
接下来$n$行,每行两个整数$X_i,Y_i$。


输出格式

输出到文件$rectangle.out$中。
一行一个整数表示答案。


样例

样例输入:

4
1 2
3 1
4 4
5 1

样例输出:

45


数据范围与提示

样例解释:

有$8$个面积大于$0$的不同矩形,以下是它们左下角和右上角的坐标:
$(1,1),(3,2);(1,1),(4,4);(1,1),(5,2);(1,1),(5,4)$
$(1,2),(4,4);(3,1),(4,4);(3,1),(5,4);(4,1),(5,4)$

数据范围:

对于所有数据,满足$2\\leqslant n\\leqslant 10^4,1\\leqslant X_i,Y_i\\leqslant 2500$,没有重复的点。
$\\bullet Subtask1(13\\%)$,$n\\leqslant 18$。
$\\bullet Subtask2(9\\%)$,$n\\leqslant 50$。
$\\bullet Subtask3(25\\%)$,$n\\leqslant 300$。
$\\bullet Subtask4(21\\%)$,$n\\leqslant 2500,X_i\\neq X_j,Y_i\\neq Y_j$。
$\\bullet Subtask5(19\\%)$,$n\\leqslant 2500$。
$\\bullet Subtask6(13\\%)$,没有特殊的约束。


题解

先来考虑$21\\%$的$X_i\\neq X_j,Y_i\\neq Y_j$的情况。

我们可以$n^2$枚举左右边界,那么设边界上的点为$(L,y_1)$和$(R,y_2)$。

那么只有位于$(L,R)$且纵坐标$>\\max(y_1,y_2)$和$<\\min(y_1,y_2)$的点才能做贡献,我们可以考虑树状数组,存储$\\sum y$即可(长度是变化的,但是高度不变)。

现在来考虑一般情况,每个$L$和$R$上可能有很多的点,我们依次枚举计数即可。

但是可能会出现如下图中的情况:

技术图片

显然,我们在统计答案点$1,3$和点$2,3$的贡献的时候会将紫色矩阵算重,不用担心,我们只需要将纵坐标最靠下的统计就好了。

代码实现稍繁琐。

时间复杂度:$\\Theta(nm\\log m)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int n;
int Map[2501][2501];
int tr[2][2501][2501];
bool vis[2501][2501];
long long ans;
int lowbit(int x)return x&-x;
void add(int id,int k,int x,int w)

	for(int i=x;i<=2500;i+=lowbit(i))
		tr[id][k][i]+=w;

int ask(int id,int k,int x)

	int res=0;
	for(int i=x;i;i-=lowbit(i))res+=tr[id][k][i];
	return res;

int main()

	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	
		int x,y;
		scanf("%d%d",&x,&y);
		Map[x][++Map[x][0]]=y;
	
	for(int i=1;i<=2500;i++)
	
		sort(Map[i]+1,Map[i]+Map[i][0]+1);
		Map[i][Map[i][0]+1]=2501;
	
	for(int i=1;i<=2500;i++)
	
		if(!Map[i][0])continue;
		for(int j=1;j<=Map[i][0];j++)
			if(!vis[i][Map[i][j]])
			
				vis[i][Map[i][j]]=1;
				add(1,i,Map[i][j],1);
				add(0,i,Map[i][j],Map[i][j]);
			
		for(int j=i-1;j;j--)
		
			if(!Map[j][0])continue;
			int l1=1,l2=1;
			for(int k=1;k<=Map[j][0];k++)
				if(!vis[i][Map[j][k]])
				
					vis[i][Map[j][k]]=1;
					add(1,i,Map[j][k],1);
					add(0,i,Map[j][k],Map[j][k]);
				
			int wzc=max(Map[i][1],Map[j][1]);
			while(Map[i][l1+1]<=wzc)l1++;
			while(Map[j][l2+1]<=wzc)l2++;
			while(l1<=Map[i][0]&&l2<=Map[j][0])
			
				int flag=min(Map[i][l1+1],Map[j][l2+1]);
				ans=(ans+1LL*(i-j)*((ask(0,i,flag-1)-ask(0,i,wzc-1))*ask(1,i,min(Map[i][l1],Map[j][l2]))-((ask(1,i,flag-1)-ask(1,i,wzc-1))*ask(0,i,min(Map[i][l1],Map[j][l2])))))%mod;
				wzc=flag;
				if(Map[i][l1+1]<=wzc)l1++;
				if(Map[j][l2+1]<=wzc)l2++;
			
		
	
	printf("%lld\\n",ans);
	return 0;


rp++

以上是关于[CSP-S模拟测试]:Rectangle(模拟+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

csp-s模拟测试92

[CSP-S模拟测试]:666(模拟)

[CSP-S模拟测试]:山屋惊魂(模拟)

csp-s模拟测试96

csp-s模拟测试97

csp-s模拟测试60