• BZOJ4651 NOI2016网格(割点)


      首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2。同样显然的一点是当且仅当跳蚤数量<=2且连通时无解。做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割点(即点双连通),若无答案为2,否则为1。

      现在的问题是这个图实在是太大了。正常的离散化可能仍然需要留下c2个点。这个时候发现部分分很足于是我们就可以弃疗了。

      比较直观的一点是附近没有蛐蛐的跳蚤不太可能被割开。显然只有周围八连通有蛐蛐的位置才可能成为割点。那么要判断其是否是割点还需要再取周围一圈。所以取出每个蛐蛐的周围两圈跳蚤放在一张图里,之间四连通的连边。此时若有某个蛐蛐周围两圈的跳蚤处于不同连通块,则说明跳蚤本身就不连通;否则tarjan求一发割点就可以了。注意这里割点必须与蛐蛐八连通(或在边界)才是原图的割点,正确性是显然的,但好像没想明白不这么干会有什么问题。

      map被卡常习惯了。bzoj过了,luoguT两个点。

      upd:莫名其妙的把一个完全能用数组的东西用map存了。然后对于点的初始化在新建点的时候进行,不要直接memset。就能过掉了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define ll long long
    #define N 100010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int T,n,m,c,dfn[N<<5],low[N<<5],cnt,tot,t,p[N<<5],id[5][5],fa[N<<5];
    bool tag[N<<5];
    struct data
    {
        int x,y;
        bool operator <(const data&a) const
        {
            return x<a.x||x==a.x&&y<a.y;
        }
    }a[N];
    map<data,int> f;
    int wx[4]={0,1,0,-1},wy[4]={1,0,-1,0};
    struct data2{int to,nxt;
    }edge[N<<7];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    bool tarjan(int k,int from)
    {
        dfn[k]=low[k]=++tot;int son=0;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from)
        {
            if (dfn[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
            else
            {
                if (tarjan(edge[i].to,k)) return 1;
                son++;low[k]=min(low[k],low[edge[i].to]);
                if (from!=-1&&low[edge[i].to]>=dfn[k]||son>1&&from==-1) if (tag[k]) return 1;
            }
        }
        return 0;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4651.in","r",stdin);
        freopen("bzoj4651.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read();
        while (T--)
        {
            n=read(),m=read(),c=read();f.clear();
            for (int i=1;i<=c;i++) a[i].x=read(),a[i].y=read(),f[a[i]]=-1;
            if (1ll*n*m-c<=1) {cout<<-1<<endl;continue;}
            if (1ll*n*m-c==2)
            {
                int vx[2],vy[2],t=-1;
                for (int i=1;i<=n;i++)
                    for (int j=1;j<=m;j++)
                    if (f.find((data){i,j})==f.end()) t++,vx[t]=i,vy[t]=j;
                if (vx[0]==vx[1]&&abs(vy[0]-vy[1])==1||vy[0]==vy[1]&&abs(vx[0]-vx[1])==1) cout<<-1<<endl;
                else cout<<0<<endl;
                continue;
            }
            cnt=0;t=0;
            for (int i=1;i<=c;i++)
            {
                for (int x=-2;x<=2;x++)
                    for (int y=-2;y<=2;y++)
                    if (a[i].x+x>=1&&a[i].x+x<=n&&a[i].y+y>=1&&a[i].y+y<=m)
                    {
                        if (f.find((data){a[i].x+x,a[i].y+y})==f.end())
                        f[(data){a[i].x+x,a[i].y+y}]=++cnt,id[x+2][y+2]=cnt,fa[cnt]=cnt,tag[cnt]=p[cnt]=dfn[cnt]=0;
                        else id[x+2][y+2]=f[(data){a[i].x+x,a[i].y+y}];
                        if (a[i].x+x==1||a[i].x+x==n||a[i].y+y==1||a[i].y+y==m||abs(x)<=1&&abs(y)<=1) tag[id[x+2][y+2]]=1;
                    }
                    else f[(data){a[i].x+x,a[i].y+y}]=-1,id[x+2][y+2]=-1;
                for (int x=0;x<=4;x++)
                    for (int y=0;y<=4;y++)
                        for (int k=0;k<4;k++)
                        if (x+wx[k]>=0&&x+wx[k]<=4&&y+wy[k]>=0&&y+wy[k]<=4&&~id[x][y]&&~id[x+wx[k]][y+wy[k]])
                        addedge(id[x][y],id[x+wx[k]][y+wy[k]]),fa[find(id[x+wx[k]][y+wy[k]])]=find(id[x][y]);
            }
            bool flag=1;
            for (int i=1;i<=c;i++)
            {
                int t=-1;
                for (int x=-2;x<=2;x++)
                    for (int y=-2;y<=2;y++)
                    {
                        int p=f[(data){a[i].x+x,a[i].y+y}];
                        if (~p) if (t==-1) t=find(p);else if (t!=find(p)) {flag=0;break;}
                    }
                if (!flag) break;
            }
            if (!flag) {cout<<0<<endl;continue;}
            if (n==1||m==1) {cout<<1<<endl;continue;}
            tot=0;
            for (int i=1;i<=cnt;i++)
            if (!dfn[i]&&tarjan(i,-1)) {cout<<1<<endl;flag=0;break;}
            if (flag) cout<<2<<endl;
        }
        return 0;
    }
  • 相关阅读:
    Linux下退出vi编辑模式
    Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 17 declared in library(开发日志28)
    Could not download bmob-sdk.arr(cn.bmob.android:bmob-sdk:3.7.8)(开发日志25)
    本周总结
    思考概念方式
    面试体系目录
    2020面试记录
    日志
    redis 实现分布式锁
    SpringMvc servlet 拦截器 过滤器关系和区别及执行顺序
  • 原文地址:https://www.cnblogs.com/Gloid/p/9910325.html
Copyright © 2020-2023  润新知