Problem A: 猴戏世家
考试时拿染色企图水20分结果hash冲突了,rp++
考虑离线乱搞一下,可以先把每个点最开始被哪个矩形包着求出来,然后把矩形被哪个矩形包着求出来。
这样点作为对矩形的贡献成为矩形的权,矩形连边后形成一把森林。
按y从大到小进行扫描线,拿set维护这个扫描线,每次加入矩形时把自己左边比自己晚的扔掉,然后随便维护一下连边和权值。
然后考虑到每个矩形可以对完全包含它的矩形做贡献,于是我们倒序删除矩形,维护一个带权并查集,每次把贡献扔给父亲就可以了
Code:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
const int N=6e5+10;
int n,m,mx[N],my[N],qx[N],qy[N],d[N],cnt;
struct beecute
{
int p,id;
beecute(){}
beecute(int p,int id){this->p=p,this->id=id;}
bool friend operator <(beecute a,beecute b){return a.p==b.p?a.id<b.id:a.p<b.p;}
};
std::vector<beecute> bee[N];
std::set <beecute> s;
std::set <beecute>::iterator it;
int par[N],f[N],val[N],ans[N];
int Find(int x){return f[x]=f[x]==x?x:Find(f[x]);}
void Merge(int x,int y)
{
f[x]=Find(y);
val[f[x]]+=val[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",mx+i,my+i),d[++cnt]=my[i];
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d%d",qx+i,qy+i),d[++cnt]=qy[i],f[i]=i;
std::sort(d+1,d+1+cnt);
cnt=std::unique(d+1,d+1+cnt)-d-1;
for(int i=1;i<=n;i++)
{
my[i]=std::lower_bound(d+1,d+1+cnt,my[i])-d;
bee[my[i]].push_back(beecute(mx[i],0));
}
for(int i=1;i<=m;i++)
{
qy[i]=std::lower_bound(d+1,d+1+cnt,qy[i])-d;
bee[qy[i]].push_back(beecute(qx[i],i));
}
for(int i=cnt;i;i--)
{
std::sort(bee[i].begin(),bee[i].end());
for(int j=bee[i].size()-1;~j;j--)
{
int id=bee[i][j].id;
it=s.lower_bound(bee[i][j]);
if(id)
{
if(it!=s.end())
par[id]=it->id;
if(it==s.begin()) {s.insert(bee[i][j]);continue;}
--it;
while(it!=s.begin()&&it->id>id)
s.erase(it--);
if(!s.empty()&&it==s.begin()&&it->id>id)
s.erase(it);
s.insert(bee[i][j]);
}
else if(it!=s.end())
++val[it->id];
}
}
for(int i=m;i;i--)
{
ans[i]=val[i];
Merge(i,par[i]);
}
for(int i=1;i<=m;i++) printf("%d
",ans[i]);
return 0;
}
2019.1.18