全球覆盖 哈希
题目描述
小黑正在研发一款全球定位软件,想用它来定位小白的坐标。
具体来说,地球可以看做一个(X imes Y)的网格矩阵,横纵坐标范围分别是([0, X))和([0, Y)),由于地球是球形结构,网格的上边界和下边界是相通的,左边界和右边界也是相通的。
现在小黑获得了(n)组坐标对,每组坐标对含有两个点的坐标((x_i,0 , y_i,0 ), (x_i,1 , y_i,1 )),表示地球上一个两边平行于坐标轴的矩形的两个对角顶点,而小白就在这个矩形内部。
然而,由于地球是球形结构,确定了坐标对后仍然有多种可能的“矩形”(如下
图所示)。小黑想知道最多可能有多少面积的网格出现在所有“矩形”的交集之中,
以方便他确定小白的位置。每个单元格的面积为(1)。
于是他把这个问题交给你了。
输入格式
从文件 (globe.in) 中读入数据。
第一行三个正整数(n, X, Y),含义如题目描述。
接下来n行,每行四个正整数(x_i,0 , y_i,0 , x_i,1 , y_i,1) ,描述一组坐标对。所有数据始终保
证有(x_i,0 < x_i,1 , y_i,0 < y_i,1) 。
输出格式
输出到文件 (globe.out) 中。
一行,一个整数,表示所求的答案。
样例 1 输入
2 10 7
2 1 8 6
4 2 5 4
样例 1 输出
15
样例 1 解释
样例中的情况和题目中图片一致,其中第三种情况的面积最大。
样例 2
见下发文件中的(globe2.in)和(globe2.ans)。
数据范围
对于前(10\%) 的数据,(n ≤ 10)。
对于前(20\%) 的数据,(n ≤ 20)。
对于另(50\%) 的数据,(n ≤ 3000)。
对于(100\%) 的数据,(n ≤ 500000,2 ≤ X, Y ≤ 10 9 , 0 ≤ x_0 , x_1 < X, 0 ≤ y_0 , y_1 < Y)。
分析
我们可以发现横纵坐标互不相关,因此可以对于横纵坐标分别枚举求出最大值,再相乘即可
现在考虑怎么单独求出横坐标或者纵坐标的最大值
显然,我们所选择的线段一定是被两组相邻的线段所截得的
而且如果我们要把多个线段拼到一起的话,这些线段必须满足截得它们的线段的价值相同
比如说上面这一幅图,如果我们去找能与(1)号线段合并的线段,那么我们就去看其它四条线段两端的颜色是否(1)好线段的颜色相同,我们发现(5)号线段满足这个条件,那么我们就把(1)号线段和(5)号线段合并
同理,我们还可以把(2)号线段和(4)号线段合并,而(3)号线段没有可以与它合并的
那么暴力的思路就是用(n^2)的效率去枚举两条线段看它们是否能合并在一起
实际上,我们可以对与每条线段取一个贡献的哈希值,将这些哈希值存在哈希表里,每次加入线段时遇到哈希值相同的就合并
合并时取一个最大值即可
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=2e6+5;
typedef unsigned long long ll;
const ll bas=131;
int ans=0;
struct m_hash{
static const ll Mod=261807;
struct asd{
int next,jz;
ll val;
}b[maxn];
int head[maxn],tot;
m_hash(){
memset(head,-1,sizeof(head));
tot=1;
}
void ad(int cd,ll val){
int now=val%Mod;
for(int i=head[now];i!=-1;i=b[i].next){
ll u=b[i].val;
if(u==val){
b[i].jz+=cd;
ans=std::max(ans,b[i].jz);
return;
}
}
b[tot].val=val;
b[tot].jz=cd;
ans=std::max(ans,b[tot].jz);
b[tot].next=head[now];
head[now]=tot++;
}
}mp1,mp2;
struct asd{
int val,id,jud;
asd(){}
asd(int aa,int bb,int cc){
val=aa,id=bb,jud=cc;
}
}a[maxn],b[maxn];
bool cmp(asd aa,asd bb){
return aa.val<bb.val;
}
int n,x,y;
ll mi[maxn];
int solve1(){
std::sort(a+1,a+n*2+1,cmp);
ll now=0;
for(int i=2;i<=n*2;i++){
now=now+mi[a[i-1].id]*a[i].jud;
mp1.ad(a[i].val-a[i-1].val,now);
}
mp1.ad(a[1].val,0);
mp1.ad(x-a[n*2].val,0);
return ans;
}
int solve2(){
ans=0;
std::sort(b+1,b+n*2+1,cmp);
ll now=0;
for(int i=2;i<=n*2;i++){
now=now+mi[b[i-1].id]*b[i].jud;
mp2.ad(b[i].val-b[i-1].val,now);
}
mp2.ad(b[1].val,0);
mp2.ad(y-b[n*2].val,0);
return ans;
}
int main(){
n=read(),x=read(),y=read();
mi[0]=1;
for(int i=1;i<=n;i++){
a[i].val=read();
b[i].val=read();
a[i+n].val=read();
b[i+n].val=read();
a[i].id=b[i].id=a[i+n].id=b[i+n].id=i;
a[i].jud=b[i].jud=1;
a[i+n].jud=b[i+n].jud=-1;
mi[i]=mi[i-1]*bas;
}
printf("%lld
",1LL*solve1()*solve2());
return 0;
}