LOJ2760题解

请叫我挂分大师。

没清空导致 100pts->0pts 数组还开大了 MLE,不愧是我。

对于连通块计数,可以考虑的一个东西叫做平面图欧拉定理:\(V+F=E+2\)

其中 \(V\) 是节点数,\(F\) 是区域数,\(E\) 是边数。

证明就是说,考虑一棵树一定是平面图,加上一条边成环之后一定会多出来一个区域。

然后再加上最外面有一个区域,答案就是 \(F=E-V+1+1\)

回到这个题,容易发现这道题的图是一个平面图,但是可能不连通。

对于不连通非常好解决,假设我们只计数内部的区域那么答案就是 \(E-V+1\),然后不连通的情况下,新生成的区域只会和自身所在连通块有关。所以答案是 \(\sum E-\sum V+F\),这里的 \(F\) 表示连通块的数量。

可以发现,只需要计算每条裁剪线与哪些相交了即可计算出点数和边数,离线线段树即可统计。

连通块数量略有麻烦。考虑相交的两条裁剪线连一条边,这个过程可以使用上述计算边数和点数类似的方法线段树优化建图。

想到了平面图欧拉定理就不难了其实,主要问题是有点缝+难写,比如这个人清空的长度出问题了就挂了巨大多分。

记得把坐标离散化。

#include<algorithm>
#include<cstdio>
#include<cctype>
#include<vector>
namespace SOLVE{
	const int M=2e5+114;
	int n,m,W,H,k,lim,ege,tot,x1[M],y1[M],x2[M],y2[M],h[M*80];int len,lsh[M];bool vis[M*80];
	std::vector<int>Add[M],Del[M],Qry[M],x,y;int sum[M<<2];
	struct Edge{
		int v,nx;
	}e[M*80];
	inline void AE(const int&u,const int&v){
		e[++ege]=(Edge){v,h[u]};h[u]=ege;
	}
	inline int read(){
		int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
	}
	struct SOG{
		int id[M<<2];
		inline void Build(const int&u,const int&L=1,const int&R=lim){
			id[u]=-1;if(L==R)return;const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);
		}
		inline void update(const int&u){
			if(!~id[u<<1]&&!~id[u<<1|1])id[u]=-1;else id[u]=++tot;
			if(~id[u<<1])AE(id[u],id[u<<1]);if(~id[u<<1|1])AE(id[u],id[u<<1|1]);
		}
		inline void Ins(const int&u,const int&x,const int&w,const int&L=1,const int&R=lim){
			if(L==R)return void(id[u]=w);const int&mid=L+R>>1;
			x<=mid?Ins(u<<1,x,w,L,mid):Ins(u<<1|1,x,w,mid+1,R);update(u);
		}
		inline void Lnk(const int&u,const int&l,const int&r,const int&v,const int&L=1,const int&R=lim){
			if(l>R|L>r)return;if(l<=L&&R<=r)return~id[u]&&(AE(v,id[u]),0),void();
			const int&mid=L+R>>1;Lnk(u<<1,l,r,v,L,mid);Lnk(u<<1|1,l,r,v,mid+1,R);
		}
	}sog;
	struct SGT{
		int BIT[M];
		inline void Add(int x,const int&w){
			while(x<=lim)BIT[x]+=w,x+=x&-x;
		}
		inline int Qry(int x){
			int sum(0);while(x>=1)sum+=BIT[x],x-=x&-x;return sum;
		}
		inline int Qry(const int&L,const int&R){
			return Qry(R)-Qry(L-1);
		}
	}sgt;
	inline void DFS(const int&u){
		vis[u]=true;for(int E=h[u];E;E=e[E].nx)if(!vis[e[E].v])DFS(e[E].v);
	}
	inline void main(){
		long long ans(0);W=read();H=read();k=read();tot=k+4;
		for(int i=1;i<=k;++i){
			x1[i]=read();y1[i]=read();x2[i]=read();y2[i]=read();
			if(x1[i]==x2[i])x.push_back(i);if(y1[i]==y2[i])y.push_back(i);
		}
		++k;x1[k]=0;y1[k]=0;x2[k]=W;y2[k]=0;y.push_back(k);
		++k;x1[k]=W;y1[k]=0;x2[k]=W;y2[k]=H;x.push_back(k);
		++k;x1[k]=0;y1[k]=H;x2[k]=W;y2[k]=H;y.push_back(k);
		++k;x1[k]=0;y1[k]=0;x2[k]=0;y2[k]=H;x.push_back(k);
		len=0;for(int i=1;i<=k;++i)lsh[++len]=x1[i],lsh[++len]=x2[i];
		std::sort(lsh+1,lsh+len+1);n=std::unique(lsh+1,lsh+len+1)-lsh-1;
		for(int i=1;i<=k;++i){
			x1[i]=std::lower_bound(lsh+1,lsh+n+1,x1[i])-lsh;x2[i]=std::lower_bound(lsh+1,lsh+n+1,x2[i])-lsh;
		}
		len=0;for(int i=1;i<=k;++i)lsh[++len]=y1[i],lsh[++len]=y2[i];
		std::sort(lsh+1,lsh+len+1);m=std::unique(lsh+1,lsh+len+1)-lsh-1;
		for(int i=1;i<=k;++i){
			y1[i]=std::lower_bound(lsh+1,lsh+m+1,y1[i])-lsh;y2[i]=std::lower_bound(lsh+1,lsh+m+1,y2[i])-lsh;
		}
		lim=m;sog.Build(1);for(int i=1;i<=lim;++i)sgt.BIT[i]=0;
		for(int&id:y)Add[x1[id]].push_back(id),Del[x2[id]+1].push_back(id);
		for(int&id:x)Qry[x1[id]].push_back(id);
		for(int i=1;i<=n;++i){
			for(int&id:Del[i])sog.Ins(1,y1[id],-1),sgt.Add(y1[id],-1);
			for(int&id:Add[i])sog.Ins(1,y1[id],id),sgt.Add(y1[id],1);
			for(int&id:Qry[i]){
				int w=sgt.Qry(y1[id],y2[id]);sog.Lnk(1,y1[id],y2[id],id);if(w)--ans;
			}
		}
		for(int i=1;i<=m;++i){
			std::vector<int>().swap(Add[i]);std::vector<int>().swap(Del[i]);std::vector<int>().swap(Qry[i]);
		}
		lim=n;sog.Build(1);for(int i=1;i<=lim;++i)sgt.BIT[i]=0;
		for(int&id:x)Add[y1[id]].push_back(id),Del[y2[id]+1].push_back(id);
		for(int&id:y)Qry[y1[id]].push_back(id);
		for(int i=1;i<=m;++i){
			for(int&id:Del[i])sog.Ins(1,x1[id],-1),sgt.Add(x1[id],-1);
			for(int&id:Add[i])sog.Ins(1,x1[id],id),sgt.Add(x1[id],1);
			for(int&id:Qry[i]){
				int w=sgt.Qry(x1[id],x2[id]);sog.Lnk(1,x1[id],x2[id],id);if(w)ans+=w-1;
			}
		}
		for(int i=1;i<=k;++i)if(e[h[i]].v&&!vis[i])DFS(i),++ans;printf("%lld",ans);
	}
}
signed main(){
	SOLVE::main();
}
//F+V=E+2
//\sum E-V+1=\sum E-\sum V-cnt
posted @ 2022-09-12 16:38  Prean  阅读(15)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};