【CF471E】MUH and Lots and Lots of Segments 掃描線+並查集+線段樹+set

【CF471E】MUH and Lots and Lots of Segments

題意:給你平面上n條水平或豎直的,端點在整點處的線段。你須要去掉一些線段的一些部分,使得剩下的圖形:1.連通,2.無環,3.端點依舊位於整點處。ios

$n\le 2\times 10^5$spa

題解:若是把整點當作點的話,那麼這題讓你求的就是一棵生成樹。一棵生成樹的邊數就是這個連通塊內點數-1,因此咱們找到最大的連通塊將其點數-1就是答案。blog

具體實現中,咱們先進行掃描線,用並查集維護連通性,用線段樹快速查找區間中點的數量以及一個點的前驅後繼,用set維護全部所在連通塊與後繼所在連通塊不一樣的點便可。get

不知道爲何思考的過程當中想到了Kruskal。string

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,np,nq;
int f[maxn<<1],org[maxn<<1];
ll ans;
ll ref[maxn<<1];
struct edge
{
	int l,r,x;
}p[maxn],q[maxn<<1];
ll s[maxn<<3],sum[maxn<<1];
set<int> st;
set<int>::iterator it;
bool cmp(const edge &a,const edge &b)
{
	return (a.x==b.x)?(a.r>b.r):(a.x<b.x);
}
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
void updata(int l,int r,int x,int a,int b)
{
	s[x]+=b;
	if(l==r)	return ;
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b);
	else	updata(mid+1,r,rson,a,b);
}
int count(int l,int r,int x,int a,int b)
{
	if(a>b)	return 0;
	if(a<=l&&r<=b)	return s[x];
	int mid=(l+r)>>1;
	if(b<=mid)	return count(l,mid,lson,a,b);
	if(a>mid)	return count(mid+1,r,rson,a,b);
	return count(l,mid,lson,a,b)+count(mid+1,r,rson,a,b);
}
int find(int l,int r,int x,int a)
{
	if(l==r)	return l;
	int mid=(l+r)>>1;
	if(a<=s[lson])	return find(l,mid,lson,a);
	return find(mid+1,r,rson,a-s[lson]);
}
inline int pre(int x)
{
	int t=count(1,m,1,1,x);
	if(t==1)	return -1;
	return find(1,m,1,t-1);
}
inline int nxt(int x)
{
	int t=count(1,m,1,1,x);
	if(t==s[1])	return -1;
	return find(1,m,1,t+1);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,j,a,b,c,d;
	ll tmp;
	for(i=1;i<=n;i++)
	{
		a=rd(),b=rd(),c=rd(),d=rd();
		if(b==d)
		{
			q[++nq].x=a,q[nq].l=b,q[nq].r=c-a+1;
			q[++nq].x=c,q[nq].l=b,q[nq].r=0;
			ref[++m]=b;
		}
		else
		{
			p[++np].x=a,p[np].l=b,p[np].r=d;
			ref[++m]=b,ref[++m]=d;
			ans=max(ans,ll(d-b));
		}
	}
	sort(ref+1,ref+m+1);
	for(i=1,j=0,ref[0]=-1<<30;i<=m;i++)	if(ref[i]!=ref[j])	ref[++j]=ref[i];
	m=j;
	for(i=1;i<=nq;i++)	q[i].l=lower_bound(ref+1,ref+m+1,q[i].l)-ref,f[i]=i;
	for(i=1;i<=np;i++)	p[i].l=lower_bound(ref+1,ref+m+1,p[i].l)-ref,p[i].r=lower_bound(ref+1,ref+m+1,p[i].r)-ref;
	sort(p+1,p+np+1,cmp);
	sort(q+1,q+nq+1,cmp);
	for(i=j=1;i<=np;i++)
	{
		while(j<=nq&&(q[j].x<p[i].x||(q[j].x==p[i].x&&q[j].r)))
		{
			a=q[j].l,b=q[j].r;
			if(b)
			{
				org[a]=j,sum[j]=b;
				st.insert(a);
				updata(1,m,1,a,1);
				c=pre(a);
				if(c!=-1)	st.insert(c);
			}
			else
			{
				it=st.find(a);
				if(it!=st.end())	st.erase(it);
				c=pre(a);
				if(c!=-1)	st.insert(c);
				updata(1,m,1,a,-1);
			}
			j++;
		}
		tmp=ref[p[i].r]-ref[p[i].l]+1-count(1,m,1,p[i].l,p[i].r);
		a=p[i].l-1,c=nxt(a);
		if(c<=p[i].r)
		{
			sum[find(org[c])]+=tmp;
			while(1)
			{
				it=st.lower_bound(p[i].l);
				if(it==st.end()||(*it)>p[i].r)	break;
				a=*it,c=nxt(a);
				if(c==-1||c>p[i].r)	break;
				st.erase(it);
				b=find(org[a]),d=find(org[c]);
				if(b!=d)	sum[d]+=sum[b],f[b]=d;
			}
		}
	}
	for(i=1;i<=nq;i++)	ans=max(ans,sum[i]-1);
	printf("%lld",ans);
	return 0;
}
相關文章
相關標籤/搜索