洛谷P5962 [BOI2004]ships 船

洛谷题目

本题不难发现是找连通块,但是这样做会 \(M\) (没试过不知道会不会 \(T\)),所以我们再考虑优化,观察输入,会发现给的是区间,所以我们只需要把区间存下来,把相邻两行相交的区间合并就行了。

\(line1\) 存当前行每艘船的位置,\(line2\) 存上一行每艘船的位置。都是结构体,包括船的左端点 \(l\),右端点 \(r\),编号 \(pos\)

并查集,当然要有 \(f\) 数组,然后再用 \(siz\) 存船的大小。

找祖先时路径压缩,合并时判断两个 \(siz\) 的大小,把小的接在大的下面。

inline int Find(int x)
{
	return f[x]==x?x:f[x]=Find(f[x]);
}

inline void Union(int a,int b)
{
	int fa=Find(a),fb=Find(b);
	if(fa==fb) return;
	if(siz[fa]>siz[fb]) f[fb]=fa,siz[fa]+=siz[fb];
	else f[fa]=fb,siz[fb]+=siz[fa];
}

本题输入也比较恶心,没见过这样的输入,不过也没办法。

可以先输入一个字符串,然后枚举一遍,把数读出来。

inline int read(int &pos)
{
	int res=0;
	while(s[pos]>='0'&&s[pos]<='9')
		res=res*10+s[pos++]-'0';
	return res;
}

其他就没什么了。

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000010

using namespace std;

struct node
{
	int l,r,pos;	//l:左端点,r:右端点,pos:编号 
}line1[N],line2[N];	//line1:当前行,line2:上一行 
int n,len1,len2;
int f[N],siz[N],cnt,ans[1010];	//f:父亲,siz:大小,cnt:船的个数,ans:输出时的桶 
char s[N];	//输入 

inline int read(int &pos)
{
	int res=0;
	while(s[pos]>='0'&&s[pos]<='9')
		res=res*10+s[pos++]-'0';
	return res;
}

inline int creat(int x)	//新建船 
{
	f[++cnt]=cnt;
	siz[cnt]=x;
	return cnt;
}

inline int Find(int x)
{
	return f[x]==x?x:f[x]=Find(f[x]);
}

inline void Union(int a,int b)
{
	int fa=Find(a),fb=Find(b);
	if(fa==fb) return;
	if(siz[fa]>siz[fb]) f[fb]=fa,siz[fa]+=siz[fb];
	else f[fa]=fb,siz[fb]+=siz[fa];
}

int main()
{
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
	{
		memcpy(line2,line1,sizeof(node)*len1);	//这里一定要这样写,因为这是结构体 
		len2=len1;
		len1=0;
		int p=0;	//枚举上一行 
		scanf("%s",s);
		int len=strlen(s);
		for(int j=0; j<len; j++)
		{
			if(s[j]==';') break;
			int x=read(j);
			int y=x;
			if(s[j]=='-') j++,y=read(j);
			line1[len1]=(node){x,y,creat(y-x+1)};
			for(; p<len2&&line2[p].r<x; p++);	//上一行的船和当前的船不相交 
			for(; p<len2&&line2[p].l<=y; p++)	//相交 
				Union(line1[len1].pos,line2[p].pos);
			len1++;
			if(p) p--;
		}
	}
	for(int i=1; i<=cnt; i++)
		if(f[i]==i) ans[siz[i]]++;
	for(int i=1000; i>=1; i--)	//答案在1000以内,直接枚举 
		if(ans[i]) printf("%d %d\n",i,ans[i]);
	return 0;
}
posted @ 2020-05-25 23:11  Acestar  阅读(164)  评论(0编辑  收藏  举报