並查集——vijos1944琵琶湖


vijos1944

下午除了訂正只做了這題啊。。

這題我感覺我的xjb算法已經有點用處了……雖然我不知道別人怎麼搞的,但是我download覺得我的做法很玄


首先,並查集並不支持斷開,所以我們不可能去順序模擬題意

因此倒序

在Ti時會有哪些點浮出水面


那首先我們二分出點(x,y)在什麼時刻浮出水面,然後把壓縮後的點向這一個時刻連一條邊……

是不是很奇怪……而且有可能會有自邊是吧。不管他,反正當森林看


這個用倒掛纔可以存下……我本來不知道怎麼存的下,因爲第一反應顯然是鄰接表啊。然後想,如果鄰接表可以存的話那邊表應該也可以存


於是邊表


暴力的做法是直接出來一個點,上下左右跑四次並查集,然後n*m判一遍。……可能和直接BFS差不多?


然後一個點浮出水面後,首先對答案的貢獻是1,然後去考慮他把上下左右連接起來對答案的貢獻,一次有效對答案的貢獻是-1,然後直接用並查集維護就可以了。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#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]<a[x][y]) t=max(t,mid),l=mid+1;else r=mid-1;
	}
	add(t,c(x,y));
}
int main()
{
	scanf("%d%d",&n,&m);
	For(i,1,n)
		For(j,1,m)	scanf("%d",&a[i][j]);
	scanf("%d",&T);
	For(i,1,T)	scanf("%d",&que[i]);
	For(i,1,n)
		For(j,1,m)	
			get(i,j);
	Dow(i,1,T)	doit(i);
	For(i,1,T)	printf("%d ",ANS[i]);
}
    






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章