https://codeforces.com/gym/101987/attachments
题意:有n个矩形,可以放两条平行与x轴的线,求怎么放置两条无限长的平行于x轴的线,使得他们与矩形相交个数最多,如果一个矩形同时与两条线相交,只算一次。
思路:与这道题https://blog.csdn.net/Wen_Yongqi/article/details/99767004有相似之处。
因为水平线无限长,所以x坐标无任何意义,只需考虑y坐标,等效成n条竖线。
求出在每个y坐标上划一条直线的穿过数目,然后枚举这条,计算另一条,用一端+1另一端-1来使得没有重复,即时刻保证前面枚举的直线不穿过线段树里的矩形。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+100;
int n,sz,x[maxn],y[maxn],cnt[maxn],ans;
vector<int> in[maxn],out[maxn];
vector<int> nums;
int addv[maxn*4],maxv[maxn*4],ql,qr,_max,v;
void maintain(int o,int l,int r)
{
int lc=o*2,rc=o*2+1;
if(l==r)maxv[o]=addv[o];
else
{
maxv[o]=max(maxv[lc],maxv[rc]);
maxv[o]+=addv[o];
}
}
void update(int o,int l,int r)
{
int lc=o*2,rc=o*2+1;
if(ql<=l && qr>=r)addv[o]+=v;
else
{
int mid=(l+r)/2;
if(ql<=mid)update(lc,l,mid);
if(qr>mid)update(rc,mid+1,r);
}
maintain(o,l,r);
}
void query(int o,int l,int r,int add)
{
if(ql<=l && qr>=r)_max=max(_max,maxv[o]+add);
else
{
int lc=o*2,rc=o*2+1;
int mid=(l+r)/2;
if(ql<=mid)query(lc,l,mid,add+addv[o]);
if(qr>mid)query(rc,mid+1,r,add+addv[o]);
}
}
void init()
{
cin>>n;
int tmp;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&tmp,&y[i],&tmp,&x[i]);
nums.push_back(x[i]);
nums.push_back(y[i]);
}
sort(nums.begin(),nums.end());
nums.erase(unique(nums.begin(),nums.end()),nums.end());
sz=nums.size();
for(int i=1;i<=n;i++)
{
x[i]=lower_bound(nums.begin(),nums.end(),x[i])-nums.begin()+1;
y[i]=lower_bound(nums.begin(),nums.end(),y[i])-nums.begin()+1;
}
}
int main()
{
//freopen("input.in","r",stdin);
init();
for(int i=1;i<=n;i++)
{
in[x[i]].push_back(i);
out[y[i]+1].push_back(i);
ql=x[i],qr=y[i],v=1;
update(1,1,sz);
}
for(int i=1;i<=sz;i++)
{
ql=qr=i;
_max=0;
query(1,1,sz,0);
cnt[i]=_max;
}
for(int i=1;i<=sz;i++)
{
for(int j=0;j<in[i].size();j++)
{
ql=x[in[i][j]],qr=y[in[i][j]],v=-1;
update(1,1,sz);
}
for(int j=0;j<out[i].size();j++)
{
ql=x[out[i][j]],qr=y[out[i][j]],v=1;
update(1,1,sz);
}
ql=1,qr=sz,_max=0;
query(1,1,sz,0);
ans=max(ans,cnt[i]+_max);
}
cout<<ans<<endl;
return 0;
}