全球覆蓋 雜湊
題目描述
小黑正在研發一款全球定位軟體,想用它來定位小白的座標。
具體來說,地球可以看做一個\(X \times 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\n",1LL*solve1()*solve2());
return 0;
}