猴戏世家 解题报告

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

原文地址:https://www.cnblogs.com/butterflydew/p/10289307.html