zoukankan      html  css  js  c++  java
  • 3.31考试T2

    题目描述

    有一个(n*m)的地图,把左边界和右边界粘起来使得形成一个圆柱,现在要不断地挖去其中的格子,要求任何时候都存在一条从最上方到最下方的路径(四联通),如果某次操作不满足要求则不做,问最后有多少次操作是成功的。

    题解

    从上到下四联通可以转化成从左到右删去的点不能够八联通,考虑怎么判断是否八联通。

    首先我们将地图复制一遍,左边一份,右边一份,每次在左边和右边依次加入删去的点,然后我们对于删去的点进行维护。

    我们使用并查集维护联通块,每个点的(fa)代表它所在的联通块中删去最早的点。

    如果加入的两个点所在的联通块相同的话,由于这两个点本质上又是一个点,所以就形成了从左到右的八联通通道。

    注意:额外判断(m=1)时,加入任何一个点肯定会导致从左到右删去的点能够八联通。

    #include <iostream>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int N = 6e5 + 5;
    int n, m, Q, ans, fa[N], cnt, vis[3005][6005], pos[N];
    int nx[10] = {0, 0, 0, 1, 1, 1, -1, -1, -1};
    int ny[10] = {0, 1, -1, 0, 1, -1, 0, 1, -1};
    inline int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
    int way(int x, int y)
    {
    	if(m == 1) return 0; int u, v; cnt ++;
    	for(int k = 1; k <= 2; k ++)
    	{
    		if(k == 1) u = x, v = y; else u = x, v = y + m;
    		for(int i = 1; i <= 8; i ++)
    		{
    			int uu = u + nx[i], vv = v + ny[i];
    			if(uu < 1 || uu > n) continue;
    			if(vv > 2 * m) vv -= 2 * m; else if(vv <= 0) vv += 2 * m;
    			if(vis[uu][vv])
    			{
    				if(k == 1) pos[find(vis[uu][vv])] = cnt;
    				else if(pos[find(vis[uu][vv])] == cnt) return 0;
    			}
    		}
    	}
    	return 1;
    }
    int main()
    {
    	n = read(); m = read(); Q = read(); int x, y;
    	for(int i = 1; i <= 2 * Q; i ++) fa[i] = i;
    	for(int num = 1, u, v; num <= Q; num ++)
    	{
    		x = read(); y = read();
    		if(way(x, y))
    		{
    			vis[x][y] = num; vis[x][y + m] = num + Q;
    			for(int k = 1; k <= 2; k ++)
    			{
    				if(k == 1) u = x, v = y; else u = x, v = y + m;
    				for(int i = 1; i <= 8; i ++)
    				{
    					int uu = u + nx[i], vv = v + ny[i];
    					if(uu < 1 || uu > n) continue;
    					if(vv > 2 * m) vv -= 2 * m; else if(vv <= 0) vv += 2 * m;
    					if(vis[uu][vv]) fa[find(vis[u][v])] = find(vis[uu][vv]);
    				}
    			}
    			ans ++;
    		}
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    大数加法、乘法实现的简单版本
    hdu 4027 Can you answer these queries?
    zoj 1610 Count the Colors
    2018 徐州赛区网赛 G. Trace
    1495 中国好区间 尺取法
    LA 3938 动态最大连续区间 线段树
    51nod 1275 连续子段的差异
    caioj 1172 poj 2823 单调队列过渡题
    数据结构和算法题
    一个通用分页类
  • 原文地址:https://www.cnblogs.com/Sunny-r/p/12606637.html
Copyright © 2011-2022 走看看