ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[JOISC 2017 Day 1] 港口设施

2022-06-12 09:35:47  阅读:142  来源: 互联网

标签:return fa int 线段 JOISC 端点 区间 2017 Day


一、题目

点此看题

二、解法

首先考虑只有一个港口的情况,发现合法的充要条件是所有 \([a,b]\) 不交。

由于两个港口是独立的,所以问题转化成:求出有多少种二染色方案,使得同色的线段不交。我们把满足 \(a<c<b<d\) 的线段 \([a,b]\) 和 \([c,d]\) 之间连一条边,然后问题就变成了求连通块个数或者判断无解。

暴力连边是 \(O(n^2)\) 的,这东西貌似不太好线段树优化建图。我们考虑按右端点从小到大扫描所有线段 \([a,b]\),并且维护右端点更大的线段组成的集合 \(S\),那么当前点连接的点是 \(S\) 中的一段连续区间(左端点在 \([a,b]\) 中)

一个关键的 \(\tt observation\) 是:一段区间被连接后的效果是,区间中的点必然同色

所以可以维护 \(nx_i\) 表示和点 \(i\) 同色的点最多延伸到哪里,那么修改变成暴力访问一段区间,并且把这段区间的 \(nx\) 全部指向区间的右端点。这等价于访问一条链并且修改它们的 \(fa\) 为链顶,所以可以套用并查集路径压缩的复杂度分析

具体实现中,把左右端点拍到数轴上,然后扫描这个数轴。如果遇到左端点就把它加入 \(S\) 中,如果遇到右端点就区间连边,并且把它从 \(S\) 中删除,维护 \(S\) 也可以用并查集。时间复杂度 \(O(n\log n)\)

#include <cstdio>
#include <vector>
using namespace std;
const int M = 2000005;
const int MOD = 1e9+7;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,a[M],b[M],c[M],l[M],nx[M],fa[M];
vector<int> g[M];
int find(int x)
{
	if(x!=fa[x]) fa[x]=find(fa[x]);
	return fa[x];
}
int qkpow(int a,int b)
{
	int r=1;
	while(b>0)
	{
		if(b&1) r=1ll*r*a%MOD;
		a=1ll*a*a%MOD;
		b>>=1;
	}
	return r;
}
int dfs(int u)
{
	for(int v:g[u])
	{
		if(~c[v])
		{
			if(c[v]==c[u]) return 0;
			continue;
		}
		c[v]=c[u]^1;if(!dfs(v)) return 0;
	}
	return 1;
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)
		b[read()]=b[read()]=i,c[i]=-1;
	for(int i=1;i<=2*n;i++)
		fa[i]=nx[i]=i;
	for(int i=1;i<=2*n;i++)
	{
		int u=b[i];
		if(!l[u]) {a[++m]=u,l[u]=m;continue;}
		for(int j=fa[l[u]]=find(l[u]+1);j<=m;)
		{
			g[a[j]].push_back(u);
			g[u].push_back(a[j]);
			int t=find(nx[j]+1);nx[j]=m;j=t;
		}
	}
	for(int i=1;i<=n;i++)
		if(c[i]==-1 && (k++,c[i]=0,!dfs(i)))
			{puts("0");return 0;}
	printf("%d\n",qkpow(2,k));
}

标签:return,fa,int,线段,JOISC,端点,区间,2017,Day
来源: https://www.cnblogs.com/C202044zxy/p/16367385.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有