[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++

原文地址:https://www.cnblogs.com/wzc521/p/11619495.html

时间: 2024-11-06 09:51:29

[CSP-S模拟测试]:Rectangle(模拟+树状数组)的相关文章

4.4 省选模拟赛 拉格朗日计数 树状数组+容斥.

像这种计数 问题什么的 是最讨厌的了... 考虑是环往环后面再续一段 暴力枚举前两个数字 树状数组统计第三个数的个数 n^2log. 考虑只枚举第个数 发现由于边界问题什么的很难处理. 再将枚举直接放到环上 发现边界问题没有了 不过存在 枚举第二个数之后 有 123 231 312 这三种形式. 第一种形式很好统计 预处理一下左边有多少个数字比自己小即可. 考虑第二种和第三种形式 很难在枚举2的时候统计出来这两种形式 考虑容斥 231=XX1-321. 312=3XX-321. 发现XX1和3X

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

题目描述 有一棵$n$个点的以$1$为根的树,以及$n$个整数变量$x_i$.树上$i$的父亲是$f_i$,每条边$(i,f_i)$有一个权值$w_i$,表示一个方程$x_i+x_{f_i}=w_i$,这$n−1$个方程构成了一个方程组.现在给出$q$个操作,有两种类型:$\bullet 1\ u\ v\ s$,表示询问加上$x_u+x_v=s$这个方程后,整个方程组的解的情况.具体来说,如果方程有唯一解,输出此时$x_1$的值:如果有无限多个解,输出$inf$:如果无解,输出$none$.注意

csp-s模拟测试56(10.2)Merchant「二分」&#183;Equation「树状数组」

又死了......T1 Merchant 因为每个集合都可以写成一次函数的形式,所以假设是单调升的函数,那么随着t越大就越佳 而单调减的函数,随着t的增大结果越小,所以不是单调的??? 但是我们的单调只需凭借t时刻的sum值是否大于S即可 如果某个单减的集合符合情况,那么他在t==0时就符合情况 如果不符合,那么他就不会作出贡献 所以可以二分 T2 Equation 一开始以为是高斯消元??? 当然不是..... 把每个xi均用x1表示,那么我们发现,对于深度奇偶不同的点,他的表示方式是不同的,

[CSP-S模拟测试]:天才绅士少女助手克里斯蒂娜(数学+树状数组)

题目描述 红莉栖想要弄清楚楼下天王寺大叔的显像管电视对“电话微波炉(暂定)”的影响. 选取显像管的任意一个平面,一开始平面内有个$n$电子,初始速度分别为$v_i$,定义飘升系数为$$\sum \limits_{1\leqslant i<j\leqslant n}|v_i\times v_j|^2$$ 由于电视会遭到大叔不同程度的暴击,电子的速度常常会发生变化.也就是说,有两种类型的操作: $\bullet 1\ p\ x\ y$将$v_p$改为$(x,y)$ $\bullet 2\ l\ r$

[CSP-S模拟测试]:小P的单调数列(树状数组+DP)

题目描述 小$P$最近喜欢上了单调数列,他觉得单调的数列具有非常多优美的性质.经过小$P$复杂的数学推导,他计算出了一个单调增数列的艺术价值等于该数列中所有书的总和.并且以这个为基础,小$P$还可以求出任意一个数列的艺术价值,它等于将这个数列顺次划分若干个极长单调区间(相邻两个单调区间的单调性必须不相同)后,每个单调区间中元素总和的平均值.比如对于数列$3\ 7\ 9\ 2\ 4\ 5$,它将被划分为$[3\ 7\ 9]\ [2]\ [4\ 5]$,其艺术价值为$\frac{19+2+9}{3}

Hdu 3887树状数组+模拟栈

题目链接 Counting Offspring Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1757    Accepted Submission(s): 582 Problem Description You are given a tree, it’s root is p, and the node is numbered fr

Codeforces 216D Spider&#39;s Web 树状数组+模拟

题目链接:http://codeforces.com/problemset/problem/216/D 题意: 对于一个梯形区域,如果梯形左边的点数!=梯形右边的点数,那么这个梯形为红色,否则为绿色, 问: 给定的蜘蛛网中有多少个红色. 2个树状数组维护2个线段.然后暴力模拟一下,因为点数很多但需要用到的线段树只有3条,所以类似滚动数组的思想优化内存. #include<stdio.h> #include<iostream> #include<string.h> #in

PAT甲题题解-1095. Cars on Campus(30)-(map+树状数组,或者模拟)

题意:给出n个车辆进出校园的记录,以及k个时间点,让你回答每个时间点校园内的车辆数,最后输出在校园内停留的总时间最长的车牌号和停留时间,如果不止一个,车牌号按字典序输出. 几个注意点: 1.如果一个车连续多次进入,只取最后一个 2.如果一个车连续多次出去,只取第一个 3.一个车可能出入校园内好几次,停留时间取总和 实际上题目就是让我们求某个时间段内的车辆总和,时间段其实就相当于一个区间,区间求和的话,很快就联想到树状数组和线段树.然而怎么将时间段和区间联系起来呢,那就存储出现在记录和询问里的所有

Codeforces 12D Ball 树状数组模拟3个元素的排序

题目链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h> #include<queue> #include<string> #include<stdlib.h> #include<a