原题:https://ac.nowcoder.com/acm/contest/889/J
题意:
二维平面上有n个矩形,每个矩形左下角是(i−1,Li)(i−1,Li), 右上角是(i,Ri)(i,Ri),矩形一开始全是黑色,平面不被矩形覆盖的地方是白色,你要把某些黑色区域涂白(一个矩形可以内部颜色不一样),使得黑色区域是一个轴对称图形并且对称轴平行于x轴,求最大黑色区域面积
思路:
经过分析发现ans关于对称轴y是一个线性的函数,而函数的最大值点只可能在 中线处取到,因此我们只需要从下往上枚举每条中线,但是y在矩形下半部分移动和在上半部分移动,这个矩形的ans关于y的单调性是相反的,因此我们需要把矩形分为上半部分和下半部分,分别维护两个集合的大小down和up(对称轴在移动过程中经过的部分矩形有多少个),下半部分的集合对答案的贡献就是(down * 移动距离 * 2) ,上半部分集合对答案的贡献是(-up * 移动距离 * 2)。
为了down和up能O(1)快速更新,需要预处理每次移动两个集合的变化。可以将每条边(底线,中线,上线)离散化,从下往上枚举离散化后的坐标,记录每次底线、中线、上线的变化数量。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
int l[maxn],r[maxn],mid[maxn];
int a[maxn*3];
int in[maxn*3],out[maxn*3],change[maxn*3];
int main(){
ll n;
cin>>n;
ll size=0;
for(ll i=1;i<=n;i++){
scanf("%d%d",&l[i],&r[i]);
l[i]=l[i]*2-1;//l[i]<=2e9
r[i]=r[i]*2-1;
mid[i]=((ll)l[i]+r[i])>>1;
a[++size]=l[i];
a[++size]=r[i];
a[++size]=mid[i];
}
sort(a+1,a+1+size);
size=unique(a+1,a+1+size)-(a+1);
for(ll i=1;i<=n;i++){
in[lower_bound(a+1,a+1+size,l[i])-a]++;
change[lower_bound(a+1,a+1+size,mid[i])-a]++;
out[lower_bound(a+1,a+1+size,r[i])-a]++;
}
ll down=0,up=0;//下半矩形个数和上半矩形个数
ll temp=0,ans=0;
down+=in[1];
for(ll i=2;i<=size;i++){//第一条是下线,对答案无贡献
temp+=((ll)(down-up)*(a[i]-a[i-1]));
ans=max(temp,ans);
down+=in[i];
down-=change[i];
up+=change[i];
up-=out[i];
}
printf("%lld
", ans);
}