UOJ220,NOI2016网格

这题细节很多啊,一开始没想通,浪费了很久。
总的来说,我是先对 nm5104 的数据暴力建图处理,然后对于大数据,答案必定大于等于0,先把所有蛐蛐形成的八连通块找出来,用并查集判断这些蛐蛐周围的跳蚤是否四联通,这样,就可以知道答案是否为0。如果不为0,再将每一个蛐蛐周围5*5范围内的跳蚤取出来建图,看看每个连通分量是否有割点即可。注意点数可达 2.2106 ,最后我的点数是设成 2.5106 。这么多点,用stl的map存是不行的,要手写hashmap。
突然好心疼当年考场上的那些OIer们。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int A=2500000,B=100010;
class graph{
    public:
        struct edge{
            int to,next;
            edge(int _to=0,int _next=0):to(_to),next(_next){}
        }e[A*8];
        int h[A],v,i,dfn[A],low[A],tim,tail,xb;
        void dfs(int x,int fa){
            tim++;
            low[x]=dfn[x]=tim;
            int child=0,i;
            for (i=h[x];i;i=e[i].next){
                int y=e[i].to;
                if (!dfn[y]){
                    child++;
                    dfs(y,x);
                    int w=low[y];
                    if (w<low[x])low[x]=w;
                    if (w>=dfn[x])iscut[x]=1;
                }else if(fa!=y && low[x]>dfn[y])low[x]=dfn[y];
            }
            if (fa<0 && child==1)iscut[x]=0;
        }
    public:
        bool iscut[A];
        void addedge(int x,int y){
            e[++xb]=edge(y,h[x]);
            h[x]=xb;
            e[++xb]=edge(x,h[y]);
            h[y]=xb;
        }
        int tarjan(){
            tim=tail=0;
            int block=0;
            memset(iscut,0,sizeof iscut);
            memset(dfn,0,sizeof dfn);
            for(int i=1;i<=v;++i)
                if(!dfn[i])dfs(i,-1),++block;
            return block;
        }
}g;
const int f1[8]={-1,-1,-1,0,0,1,1,1},f2[8]={-1,0,1,-1,1,-1,0,1};
int n,i,m,T,xb,cnt,w,x[B],y[B],u,v,s,t,j,a[A],b[A],c[A],f[A];
struct hashmap{
    static const int p=20000003;
    int h[p],nxt[A],a[A],xb,i;
    pair<pair<int,int>,int> v[A];
    inline int hash(pair<int,int> x){
        return (1ll*x.first*(n-1)+x.second)%p;
    }
    inline bool count(pair<int,int> x){
        int y=hash(x);
        for(i=h[y];i;i=nxt[i])if(v[i].first==x)return 1;
        return 0;
    }
    inline int& operator[](pair<int,int> x){
        int y=hash(x);
        for(i=h[y];i;i=nxt[i])if(v[i].first==x)break;
        if(i)return v[i].second;
            else{
                v[++xb]=make_pair(x,0);
                a[xb]=y;
                nxt[xb]=h[y];
                h[y]=xb;
                return v[xb].second;
            }
    }
    inline void insert(pair<pair<int,int>,int> x){
        int y=hash(x.first);
        v[++xb]=x;
        a[xb]=y;
        nxt[xb]=h[y];
        h[y]=xb;
    }
    inline void clear(){
        for(i=1;i<=xb;++i)h[a[i]]=0;
        xb=0;
    }
}M1,M2,M3;
pair<int,int> d[A];
pair<pair<int,int>,int> e[A];
inline bool in(int x,int y){
    return 1<=x && x<=n && 1<=y && y<=m;
}
namespace SOL{
    void main(){
        memset(g.h,0,sizeof g.h);
        g.xb=xb=0;
        for(i=1;i<=n;++i)
            for(j=1;j<=m;++j)
                if(!M1.count(make_pair(i,j))){
                    M2[make_pair(i,j)]=++xb;
                    if(in(i,j-1) && !M1.count(make_pair(i,j-1)))g.addedge(M2[make_pair(i,j-1)],xb);
                    if(in(i-1,j) && !M1.count(make_pair(i-1,j)))g.addedge(M2[make_pair(i-1,j)],xb);
                }   
        g.v=xb; 
        s=g.tarjan();
        if(s>1)puts("0");
            else if(1ll*n*m==cnt+2)puts("-1");
                    else{
                        for(i=1;i<=xb;++i)if(g.iscut[i])break;
                        if(i>xb)puts("2");
                            else puts("1");
                    }
    }
}
void dfs(int x,int y,pair<int,int> fa){
    M2.insert(make_pair(make_pair(x,y),0));
    for(int i=0;i<8;++i){
        int nx=x+f1[i],ny=y+f2[i];
        pair<int,int> p=make_pair(nx,ny);
        if(in(nx,ny) && p!=fa){
            if(M1.count(p)){
                if(!M2.count(p))dfs(nx,ny,make_pair(x,y));
            }else d[++w]=p,M3.insert(make_pair(p,w));
        }
    }
}
int gfa(int a){
    return f[a]==a?a:f[a]=gfa(f[a]);
}
int main(){ 
    //freopen("NOI2016grid24.in","r",stdin);
    //freopen("NOI2016grid.out","w",stdout);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&cnt);
        M1.clear();
        M2.clear();
        M3.clear();
        for(i=1;i<=cnt;++i){
            scanf("%d%d",x+i,y+i);
            M1.insert(make_pair(make_pair(x[i],y[i]),0));
        }
        if(1ll*n*m-cnt<2){
            puts("-1");
            continue;
        }
        if(1ll*n*m<=50000){
            SOL::main();
            continue;
        }
        if(cnt==0){
            puts(n==1 || m==1?"1":"2");
            continue;
        }
        if(cnt==1){
            if(n==1){
                if(y[1]==1 || y[1]==m)puts("1");
                    else puts("0");
                continue;
            }
            if(m==1){
                if(x[1]==1 || x[1]==n)puts("1");
                    else puts("0");
                continue;
            }
            if(((x[1]==1 || x[1]==n) && (y[1]==2 || y[1]==m-1)) || 
                ((x[1]==2 || x[1]==n-1)&& (y[1]==1 || y[1]==m)) || n==2 || m==2)puts("1");
                    else puts("2");
            continue;
        }
        for(i=1;i<=cnt;++i)
            if(!M2.count(make_pair(x[i],y[i]))){
                //if(i%100==0)printf("%d\n",i);
                M3.clear();
                w=0;
                dfs(x[i],y[i],make_pair(0,0));
                for(int j=1;j<=w;++j)f[j]=j;
                for(int j=1;j<=w;++j)
                    for(int k=0;k<8;++k)if(!f1[k] || !f2[k]){
                        int nx=d[j].first+f1[k],ny=d[j].second+f2[k];
                        int it=M3[make_pair(nx,ny)];
                        if(in(nx,ny) && it)f[gfa(j)]=gfa(it);
                    }
                int j;
                for(j=1;j<=w;++j)if(gfa(j)!=gfa(1))break;
                if(j<=w)break;
            }
        if(i<=cnt){
            puts("0");
            continue;
        }
        M2.clear();
        M3.clear();
        xb=0;
        memset(g.h,g.xb=xb=0,sizeof g.h);
        w=0;
        for(i=1;i<=cnt;++i)
            for(j=0;j<8;++j){
                u=x[i]+f1[j];
                v=y[i]+f2[j];
                if(in(u,v) && !M1.count(make_pair(u,v)) && !M2.count(make_pair(u,v)))
                    M2[make_pair(u,v)]=++xb,a[++w]=u,b[w]=v,c[w]=xb;
            }
        int z=xb;
        i=w;
        while(i){
            u=a[i];
            v=b[i];
            s=c[i--];
            for(int j=0;j<8;++j){
                int x=u+f1[j],y=v+f2[j];
                pair<int,int> p=make_pair(x,y);
                if(in(x,y) && !M1.count(p) && !M2.count(p))M2[p]=++xb,a[++w]=x,b[w]=y,c[w]=xb;
            }
        }
        for(i=1;i<=w;++i)e[i]=make_pair(make_pair(a[i],b[i]),c[i]);
        std::sort(e+1,e+w+1);
        for(i=2;i<=w;++i)
            if(e[i-1].first.first==e[i].first.first && e[i].first.second==e[i-1].first.second+1)
                g.addedge(e[i].second,e[i-1].second);
        for(i=1;i<=w;++i)e[i]=make_pair(make_pair(b[i],a[i]),c[i]);
        std::sort(e+1,e+w+1);
        for(i=2;i<=w;++i)
            if(e[i-1].first.first==e[i].first.first && e[i].first.second==e[i-1].first.second+1)
                g.addedge(e[i].second,e[i-1].second);
        g.v=xb;
        s=g.tarjan();
        for(i=1;i<=z;++i)if(g.iscut[i])break;
        if(i>z)puts("2");
            else puts("1");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值