下午除了订正只做了这题啊。。
这题我感觉我的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]);
}