并查集——vijos1944琵琶湖


vijos1944

下午除了订正只做了这题啊。。

这题我感觉我的xjb算法已经有点用处了……虽然我不知道别人怎么搞的,但是我download觉得我的做法很玄


首先,并查集并不支持断开,所以我们不可能去顺序模拟题意

因此倒序

在Ti时会有哪些点浮出水面


那首先我们二分出点(x,y)在什么时刻浮出水面,然后把压缩后的点向这一个时刻连一条边……

是不是很奇怪……而且有可能会有自边是吧。不管他,反正当森林看


这个用倒挂才可以存下……我本来不知道怎么存的下,因为第一反应显然是邻接表啊。然后想,如果邻接表可以存的话那边表应该也可以存


于是边表


暴力的做法是直接出来一个点,上下左右跑四次并查集,然后n*m判一遍。……可能和直接BFS差不多?


然后一个点浮出水面后,首先对答案的贡献是1,然后去考虑他把上下左右连接起来对答案的贡献,一次有效对答案的贡献是-1,然后直接用并查集维护就可以了。


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 1e9
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
int a[1001][1001],que[100001],n,m,T,fa[1000001],poi[1000001],f[1000001],nxt[1000001],cnt,ANS[100001],size[1000001],ans;
int dx[]={0,1,0,-1,0};
int dy[]={0,0,1,0,-1};
inline int c(int x,int y){return (x-1)*m+y;}
inline void add(int x,int y)
{
	poi[++cnt]=y;nxt[cnt]=f[x];f[x]=cnt;
}
inline int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
inline void merge(int x,int y)
{
	int tx=get(x),ty=get(y);
	fa[tx]=ty;
	if(tx!=ty)
		ans-=1;	
}
inline void doit(int x)
{
	for(int i=f[x];i;i=nxt[i])
	{
	
		int ty=(poi[i]-1)%m+1,tx=(poi[i]-1)/m+1;	
		fa[poi[i]]=poi[i];size[poi[i]]=1;
		ans++;
		For(dir,1,4)
		{
			int px=tx+dx[dir],py=ty+dy[dir];
			if(px>=1&&py>=1&&px<=n&&py<=m)	
				if(fa[c(px,py)])	
					merge(c(tx,ty),c(px,py));
		}
	}
	ANS[x]=ans;
}
inline void get(int x,int y)
{
	int l=1,r=T,t=0;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(que[mid]






你可能感兴趣的:(题库)