[NOI2016]网格

嘟嘟嘟


这题前前后后写了大半个上午……


首先答案肯定是-1,0,1,2这几种。
思路就是tarjan判有无割点。因为图太大,所以考虑“离散化”,对于每一个蛐蛐,把他周围55的跳蚤拿来建图。为什么不是33呢,因为如果一个蛐蛐在边界,3*3中的方格就会把一个跳蚤算成割点。


讲道理这题就没了,但是有特别多的细节。首先得特判各种情况,比如\(n = 1\)\(m = 1\),只有两个相邻的块,没有蛐蛐的情况……但最为重要的是,这些特判都完事后,求出来的割点还可能是“假割点”,比如这种情况就会这么建图:

因此对于每一个割点,要判断周围有没有蛐蛐。


然后我因为用了map,花了一个多点卡常结果还是有两个点TLE了。中午吃完饭换成哈希表,这两个点只用了300ms……
所以,真爱生命,远离map!

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<assert.h>
#include<ctime>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
const int maxN = 2.5e6 + 5;
const int maxe = 5e7 + 5;
const ll BAS = 998244353;
const ll mod = 2333333;
In ll read()
{
  ll ans = 0;
  char ch = getchar(), last = ' ';
  while(!isdigit(ch)) last = ch, ch = getchar();
  while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
  if(last == '-') ans = -ans;
  return ans;
}
In void write(ll x)
{
  if(x < 0) x = -x, putchar('-');
  if(x >= 10) write(x / 10);
  putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
  freopen("ha.in", "r", stdin);
  freopen("ha.out", "w", stdout);
#endif
}

#define pr pair<int, int>
#define mp make_pair

ll n, m;
int c, tot = 0;
struct Node {int x, y;}p[maxn], t[maxN];
struct Edge
{
  int nxt, to;
}e[maxe];
int head[maxN], ecnt = -1;
In void addEdge(const int& x, const int& y)
{
  //printf("-->%d %d\n", x, y);
  e[++ecnt] = (Edge){head[x], y};
  head[x] = ecnt;
}

struct Hash
{
  int head[mod], hcnt;
  pr to[maxN];
  int nxt[maxN], w[maxN];
  In void A(int x, int y, int id)
  {
    int h = (1LL * x * BAS + y) % mod;
    ++hcnt;
    nxt[hcnt] = head[h], to[hcnt] = mp(x, y), w[hcnt] = id;
    head[h] = hcnt;
  }
  In int Q(int x, int y)
  {
    int h = (1LL * x * BAS + y) % mod;
    for(int i = head[h]; i; i = nxt[i])
      if(mp(x, y) == to[i]) return w[i];
    return 0;
  }
}H;

In bool check(const int& x, const int& y)
{
  return x > 0 && x <= n && y > 0 && y <= m && ~H.Q(x, y);
}
In bool check_dis(const int& x, const int& y, const int& X, const int& Y)
{
  return abs(x - X) <= 2 && abs(y - Y) <= 2;
}

In int N(int x, int y)
{
  int tp = H.Q(x, y);
  if(!tp)
    {
      H.A(x, y, ++tot); tp = tot;
      t[tot] = (Node){x, y};
    }
  return tp;
}

int a[5][5];
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1}, dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
In void build(const int& x, const int& y, const int& X, const int& Y)
{
  int u = a[x - X + 2][y - Y + 2];
  for(int i = 0; i < 4; ++i)
    {
      int nx = x - X + dx[i] + 2, ny = y - Y + dy[i] + 2;
      if(a[nx][ny] == -1 || !check_dis(x + dx[i], y + dy[i], X, Y)) continue;
      addEdge(u, a[nx][ny]);
    }
}

In void solve(const int& x, const int& y)
{
  for(int i = -2; i <= 2; ++i)
    for(int j = -2; j <= 2; ++j)
      if((i || j) && check(x + i, y + j)) a[i + 2][j + 2] = N(x + i, y + j);
      else a[i + 2][j + 2] = -1;
  for(int i = -2; i <= 2; ++i)
    for(int j = -2; j <= 2; ++j)
      {
	if(!i && !j) continue;
	if(~a[i + 2][j + 2]) build(x + i, y + j, x, y);
      }
}

bool flg_cut = 0;
int dfn[maxN], low[maxN], cnt = 0, root;
int col[maxN], ccol = 0;
In void dfs(int now, const int& _f, const int& id)
{
  col[now] = id;
  dfn[now] = low[now] = ++cnt;
  int tp = 0;
  for(int i = head[now], v; ~i; i = e[i].nxt)
    {
      if(!dfn[v = e[i].to])
	{
	  ++tp;
	  dfs(v, now, id);
	  low[now] = min(low[now], low[v]);
	  if(low[v] >= dfn[now] && (now != root || tp > 1))
	    {
	      for(int j = 0; j < 8 && !flg_cut; ++j)
		{
		  int nx = t[now].x + dx[j], ny = t[now].y + dy[j];
		  if(nx > 0 && nx <= n && ny > 0 && ny <= m && H.Q(nx, ny) == -1) flg_cut = 1;
		}
	    }
	}
      else if(v ^ _f) low[now] = min(low[now], dfn[v]);
    }
}

In bool judge_0(const int& x, const int& y)
{
  int Col = 0;
  for(int i = -2; i <= 2; ++i)
    for(int j = -2; j <= 2; ++j)
      {
	int nx = x + i, ny = y + j;
	if((!i && !j) || !check(nx, ny)) continue;
	int tp = col[H.Q(nx, ny)];
	if(Col && Col ^ tp) return 1;
	Col = tp;
      }
  return 0;
}

In void init()
{
  ecnt = -1;
  tot = cnt = ccol = 0; flg_cut = 0;
  Mem(H.head, 0); H.hcnt = 0;
  for(int i = 1; i <= c * 25; ++i)
  dfn[i] = low[i] = col[i] = 0, head[i] = -1;
}

int main()
{
  MYFILE();
  db Beg = clock();
  int T = read();
  while(T--)
    {
      n = read(), m = read(), c = read();
      init();
      for(int i = 1; i <= c; ++i)
	{
	  p[i].x = read(), p[i].y = read();
	  H.A(p[i].x, p[i].y, -1);
	}
      for(int i = 1; i <= c; ++i) solve(p[i].x, p[i].y);
      if(!c)
	{
	  if(n * m < 3) puts("-1");
	  else puts(n == 1 || m == 1 ? "1" : "2");
	  continue;
	}
      if(n * m - c == 2)
	{
	  puts(~head[1] ? "-1" : "0");
	  continue;
	}
      if(n * m - c < 2) {puts("-1"); continue;}
      for(int i = 1; i <= tot; ++i) if(!dfn[i]) root = i, dfs(i, 0, ++ccol);
      bool flg = 0;
      for(int i = 1; i <= c && !flg; ++i)
	if(judge_0(p[i].x, p[i].y)) flg = 1;
      if(flg) puts("0");
      else
	{
	  if(n == 1 || m == 1) puts("1");
	  else puts(flg_cut ? "1" : "2");
	}
    }
  db End = clock();
  //printf("%.4lf\n", (End - Beg) / CLOCKS_PER_SEC);
  return 0;
}
posted @ 2019-05-19 14:04  mrclr  阅读(304)  评论(0编辑  收藏  举报