题意:给你n个矩形的左上角和右下角的x、y坐标,让你选两条平行于x轴的线,这两条线穿过最多不同的矩形多少个。
题解:因为线无限长,所以可以把二维的矩形看成一维的线段。线段的左端点就是右下角的y值,线段的右端点就是左上角的y值。n范围为1e5,x、y坐标范围为[-1e7,1e7],先把点离散化,然后枚举第一条直线的值,把覆盖该值的线段剔除掉,ans就是覆盖该值的线段数+剩余的覆盖某个值最多的线段数,再取个最大值。涉及区间最值和区间更新,所以用线段树维护。枚举前把离散化的点update在线段树上,枚举前先把线段按左端点由小到大排序,枚举时用一个指针j,记录当前我们遍历到哪条线段。tmp值是覆盖该值的线段数,如果当前枚举的值i大于a[j].l,tmp++,并把该线段放入一个优先队列(优先队列按右端点由小到大排序),还要把该线段从线段树上剔除。如果i大于q.top().r,表明i值已经不覆盖该线段,tmp–,把该线段加入回线段树。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 2e5+5;
int n,p[maxn],tot;
struct node
{
int l,r;
bool operator < (const node &b)const
{
return r>b.r;
}
}a[maxn];
struct tree
{
int l,r,mx,f;
}tr[maxn*4+1];
bool cmp(node a,node b)
{
return a.l < b.l;
}
void build(int k,int l,int r)
{
tr[k].l = l,tr[k].r = r;
if(l == r)
{
tr[k].mx = 0;
return;
}
int mid = (l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
}
void pushdown(int k)
{
tr[k*2].mx += tr[k].f;
tr[k*2+1].mx += tr[k].f;
tr[k*2].f += tr[k].f;
tr[k*2+1].f += tr[k].f;
tr[k].f = 0;
}
void update(int k,int l,int r,int w)
{
if(tr[k].l >= l && tr[k].r <= r)
{
tr[k].mx += w;
tr[k].f += w;
return;
}
if(tr[k].f)
pushdown(k);
int mid = (tr[k].l+tr[k].r)/2;
if(l<=mid)
update(k*2,l,r,w);
if(r>mid)
update(k*2+1,l,r,w);
tr[k].mx = max(tr[k*2].mx,tr[k*2+1].mx);
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
p[++tot] = y;
a[i].r = y;
scanf("%d%d",&x,&y);
p[++tot] = y;
a[i].l = y;
}
sort(p+1,p+1+tot);
int m = unique(p+1,p+1+tot)-p-1;
build(1,1,m);
for(int i=1; i<=n; i++)
{
a[i].l = lower_bound(p+1,p+1+m,a[i].l) - p;
a[i].r = lower_bound(p+1,p+1+m,a[i].r) - p;
update(1,a[i].l,a[i].r,1);
}
sort(a+1,a+1+n,cmp);
int ans = 0,tmp = 0;
int j = 1;
priority_queue<node>q;
for(int i=1; i<=m; i++)
{
while(j<=n && i>=a[j].l)
{
tmp++;
update(1,a[j].l,a[j].r,-1);
q.push(a[j]);
j++;
}
while(i>q.top().r)
{
tmp--;
node u = q.top();
q.pop();
update(1,u.l,u.r,1);
}
ans = max(ans,tmp+tr[1].mx);
}
printf("%d",ans);
}