并查集——vijos1944 琵琶湖

来源:互联网 发布:aso优化面试该说些什么 编辑:程序博客网 时间:2024/04/29 00:53

https://vijos.org/p/1944
并查集维护连通块水题;
并查集不支持删除的嘛,所以先把ti倒着来;
然后么再按照n*m里的数值,把每个点排个序;
这样t数组不断downto的时候n*m数组顺便线性扫过去;
扫地时候用并查集统计就好了;
一开始每个点父亲-1;
然后如果更新了一个点,父亲自己;
然后很上下左右4个点取合并;

#include<bits/stdc++.h>#define Ll long longusing namespace std;const int N=1e6+5;struct di{int x,y,v;}d[N];int a[N],ans[N],top,fa[N],sum;int n,m,p;int get(int x){    if(fa[x]==-1)return -1;    if(fa[x]==0)return x;    return fa[x]=get(fa[x]);}void check(int xx,int yy,int x,int y){    if(x<1||x>n||y<1|y>m)return;    int w=(xx-1)*m+yy;    int t=(x-1)*m+y;    int fw=get(w);    int ft=get(t);    if(ft==-1||fw==ft)return;    sum--;    fa[fw]=ft;}void work(int w){    int xx=d[w].x;    int yy=d[w].y;    int t=(xx-1)*m+yy;    int f=get(t);    if(f==-1){sum++;fa[t]=0;}    check(xx,yy,xx-1,yy);    check(xx,yy,xx+1,yy);    check(xx,yy,xx,yy-1);    check(xx,yy,xx,yy+1);}bool cmp(di a,di b){return a.v<b.v;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++){            int w=(i-1)*m+j;            fa[w]=-1;            d[w].x=i;            d[w].y=j;            scanf("%d",&d[w].v);        }    top=n*m;    sort(d+1,d+top+1,cmp);    scanf("%d",&p);    for(int i=1;i<=p;i++)scanf("%d",&a[i]);    for(int i=p;i;i--){        while(top&&d[top].v>a[i])work(top--);        ans[i]=sum;    }    for(int i=1;i<=p;i++)printf("%d ",ans[i]);}
原创粉丝点击