hihoCoder #1291 : Building in Sandbox 逆向处理+并查集维护

/**
题目:#1291 : Building in Sandbox
链接:https://hihocoder.com/problemset/problem/1291
题意:就是一个三维的空间里,按照顺序放n个木块,每个木块满足两种条件。
1,和地面相邻或者和以前放过的木块有一个相邻的面。
2,不在封闭空间内。即可从无限远到达该木块。

判断该种放木块顺序是否合法。

思路:https://www.zhihu.com/question/42406890

逆向处理,并查集维护那些可以从无限远到达的位置称为自由块。

逆向处理的木块,当前木块如果和自由块相邻且和其他不是自由块的木块相邻或者地面相邻,那么当前木块合法。
将它变成自由块。然后更新和它相邻的那些不是自由块也不是木块的位置变成自由块。(相当于打开了一个缺口,水流进去了。)

*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<algorithm>
#include<queue>
using namespace std;
typedef unsigned int ut;
typedef long long LL;
const int N = 1e5+1;
struct node
{
    int x, y, z;
}t[N];
int cube[104][104][104];///放木块的位置。
int st[2*N*10];///hash一个三维坐标的值为i+j*100+k*10000;
int outvalue = 0;///表示自由块。
int flag[104][104][104];///记录i+j*100+k*10000;
int dir[6][3] = {{1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1}};///向6个方向扩展。
int get(int i,int j,int k)
{
    return i+j*100+k*10000;
}
int Find(int x)
{
    if(x==st[x]) return x;
    return st[x] = Find(st[x]);
}
void Merge(int x,int y)
{
    int fx = Find(x);
    int fy = Find(y);
    if(fy>fx){///保证小的数为根,是为了让outvalue=0这个值始终为根。方便判断是否是自由块。
        st[fy] = fx;
    }else
    {
        st[fx] = fy;
    }
}
int main()
{
    int T;
    int n;
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        memset(cube, 0, sizeof cube);
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d",&t[i].x ,&t[i].y, &t[i].z);
            cube[t[i].x][t[i].y][t[i].z] = 1;
        }

        for(int i = 1; i <= 100; i++){
            for(int j = 1; j <= 100; j++){
                for(int k = 1; k <= 100; k++){
                    flag[i][j][k] = get(i,j,k);
                    st[flag[i][j][k]] = flag[i][j][k];
                }
            }
        }
        for(int i = 1; i <= 100; i++){
            for(int j = 1; j <= 100; j++){
                for(int k = 1; k <= 100; k++){
                    if(cube[i][j][k]) continue;
                    for(int o = 0; o < 6; o++){
                        int x = i+dir[o][0];
                        int y = j+dir[o][1];
                        int z = k+dir[o][2];
                        if(x<1||x>100||y<1||y>100||z>100){///和超出数据范围的相邻,所以是自由块。
                            st[Find(flag[i][j][k])] = outvalue;
                            continue;
                        }
                        if(z<1) continue;
                        if(cube[x][y][z]) continue;
                        Merge(flag[i][j][k],flag[x][y][z]);
                    }
                }
            }
        }
        int ans = 1;
        for(int i = n; i >= 1; i--){
            int tie = 0;///是否和上一个木块相邻或者和地面相邻。
            int out = 0;///是否和自由块相邻。
            for(int o = 0; o < 6; o++){
                int x = t[i].x+dir[o][0];
                int y = t[i].y+dir[o][1];
                int z = t[i].z+dir[o][2];
                if(x<1||x>100||y<1||y>100||z>100){
                    out = 1;
                    continue;
                }
                if(z==0){
                    tie = 1; continue;
                }
                ///!!!这里要注意判断顺序,不能直接cube[x][y][z].因为有些木块是已经被释放了的,被取走了。
                if(Find(flag[x][y][z])==outvalue){///如果这个木块已经被释放或者自由块那么与out相连。
                    out = 1;
                }else
                {
                    if(cube[x][y][z]){///没有被释放的木块。
                        tie = 1;
                    }
                }
            }
            if(tie&&out){
                st[flag[t[i].x][t[i].y][t[i].z]] = outvalue;
                for(int o = 0; o < 6; o++){
                int x = t[i].x+dir[o][0];
                int y = t[i].y+dir[o][1];
                int z = t[i].z+dir[o][2];
                if(x<1||x>100||y<1||y>100||z>100){
                    continue;
                }
                if(z==0){
                    continue;
                }
                if(cube[x][y][z]){
                    continue;
                }else
                {
                    Merge(flag[t[i].x][t[i].y][t[i].z],flag[x][y][z]);
                }
            }
            }else
            {
                ans = 0; break;
            }
        }
        printf("%s
",ans?"Yes":"No");

    }
    return 0;
}
原文地址:https://www.cnblogs.com/xiaochaoqun/p/7344551.html