首页 > 其他分享 >P1173 [NOI2016] 网格

P1173 [NOI2016] 网格

时间:2024-04-28 13:59:43浏览次数:15  
标签:adv node int 网格 std NOI2016 P1173 include define

P1173 [NOI2016] 网格

分讨+建图+点双

分析一下替换个数的上界,发现最多为 \(2\),因为最坏情况下,也仍存在一个位置只有两个出去的方向(即边缘),堵住即可。

那么现在答案就只有 \(-1\)、\(0\)、\(1\)、\(2\) 四种情况。分开讨论:

\(-1\):当图中只有一个跳蚤或者只有两只跳蚤连在一起时

\(0\):图本身不连通

\(1\):图中有割点

\(2\):除上面之外的情况

那么就有了这题的朴素做法,把网格上所有点连边,特判一下 \(-1\),再跑 tarjan 求割点即可。

考虑优化建图。我们发现图中很多点是不需要的,割点只会出现在角落或者蛐蛐旁边。所以只需要加上这些点就行:

  1. 每个角落的四个点。
  2. 每个蛐蛐旁边横纵距离之差小于 \(2\) 的点。
  3. 每个蛐蛐所在行列的最左、最右、最上、最下点。

\(1\) 的情况显然,\(2\) 是因为蛐蛐旁边的点如果需要判断割边,需要加上第二层的点,\(3\) 是为了让整幅图连通,以防误判 \(0\) 的情况。

然后这题难在建图,步骤是先找出所有的点,分别按照第一关键字为行、列分别连边。

前面的特判对于新图仍然适用,\(-1\) 的情况对应新图中的点 \(\le 1\),以及新图只有两个点并且相连;\(0\) 即跑完 tarjan 没有跑完所有点;\(1\) 为找到割边。这几个点比较隐晦,很难找到一个图来 hack。

这样子图上的点就控制在 \(O(c)\) 的数量内。由于建图需要排序所以复杂度 \(O(c\log c)\)。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <string>
#include <array>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstdlib>
#include <bitset>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

typedef long long i64;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 3e6 + 10;
int T, n, m, c;
int tot, idx;
struct node {int x, y, id;} a[N];
bool cmp1(node a, node b) {
	return a.x == b.x ? (a.y == b.y ? a.id < b.id : a.y < b.y) : a.x < b.x;
}
bool cmp2(node a, node b) {
	return a.y == b.y ? a.x < b.x : a.y < b.y;
}
void adv(int x, int y, int dx, int dy) {
	for(int i = -dx; i <= dx; i++) {
		for(int j = -dy; j <= dy; j++) {
			int sx = x + i, sy = y + j;
			if(sx >= 1 && sx <= n && sy >= 1 && sy <= m) a[++tot] = {sx, sy, 0};
		}
	}
}
struct edge {
	int to, nxt;
} e[N];
int cnt, h[N];
void add(int u, int v) {
	e[++cnt].to = v;
	e[cnt].nxt = h[u];
	h[u] = cnt;
}
int t, dfn[N], low[N], cut, rt = 1;
void tarjan(int u) {
	dfn[u] = low[u] = ++t;
	int flg = 0;
	for(int i = h[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(!dfn[v]) {
			tarjan(v);
			low[u] = std::min(low[u], low[v]);
			if(low[v] >= dfn[u]) {
				flg++;
				if(u != rt || flg > 1) cut++;
			}
		} else low[u] = std::min(low[u], dfn[v]);
	}
}
void Solve() {
	std::cin >> T;
	while(T--) {
		for(int i = 1; i <= idx; i++) dfn[i] = low[i] = h[i] = 0;
		cnt = cut = t = tot = 0;
		std::cin >> n >> m >> c;
		for(int i = 1; i <= c; i++) {
			int x, y;
			std::cin >> x >> y;
			adv(x, y, 2, 2);
			adv(1, y, 0, 0), adv(n, y, 0, 0), adv(x, 1, 0, 0), adv(x, m, 0, 0);
			a[++tot] = {x, y, -1};
		}
		adv(1, 1, 2, 2), adv(1, m, 2, 2), adv(n, 1, 2, 2), adv(n, m, 2, 2);
		std::sort(a + 1, a + tot + 1, cmp1);
		node now = {0, 0, 0};
		int tot2 = 0;
		for(int i = 1; i <= tot; i++) {
			if(a[i].x != now.x || a[i].y != now.y) {
				now = a[i], a[++tot2] = now;
			}
		}
		tot = tot2;
		idx = 0;
		for(int i = 1; i <= tot; i++) if(a[i].id != -1) a[i].id = ++idx;
		for(int i = 2; i <= tot; i++) {
			if(a[i].x == a[i - 1].x && a[i].id != -1 && a[i - 1].id != -1) {
				add(a[i].id, a[i - 1].id), add(a[i - 1].id, a[i].id);
			}
		}
		std::sort(a + 1, a + tot + 1, cmp2);
		for(int i = 2; i <= tot; i++) {
			if(a[i].y == a[i - 1].y && a[i].id != -1 && a[i - 1].id != -1) {
				add(a[i].id, a[i - 1].id), add(a[i - 1].id, a[i].id);
			}
		}
		if(idx <= 1) {
			std::cout << "-1\n";
			continue;
		}
		tarjan(1);
		if(idx == 2 && h[1]) {
            std::cout << "-1\n";
		} else if(t != idx) {
			std::cout << "0\n";
		} else {
			std::cout << (cut ? 1 : 2) << "\n";
		}
	}
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	Solve();

	return 0;
}

标签:adv,node,int,网格,std,NOI2016,P1173,include,define
From: https://www.cnblogs.com/FireRaku/p/18163588

相关文章

  • threejs 父元素 相对位置 position 网格对象
    设置position都是相对于父元素的位置设置的//导入threejsimport*asTHREEfrom"three";import{OrbitControls}from"three/examples/jsm/controls/OrbitControls.js";//创建场景sceneconstscene=newTHREE.Scene();//console.log(scene,'scene'......
  • [qt]画网格,过分简单了
    源码:#include<QImage>#include<QPainter>voiddrawLines(QImage&image){QPainterpainter(&image);QPenpen(Qt::black);pen.setWidth(2);  //设置线宽2dotpainter.setPen(pen);//绘制水平线,分8份for(inty=89;y<ima......
  • C117 莫队配合 bitset P4688 [Ynoi2016] 掉进兔子洞
    视频链接:C117莫队配合bitsetP4688[Ynoi2016]掉进兔子洞_哔哩哔哩_bilibili   LuoguP4688[Ynoi2016]掉进兔子洞//莫队配合bitsetO(n*sqrt(n))#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<bitset>usin......
  • echarts折线图 x 轴 y 轴不展示 背景图为网格 鼠标划上样式修改等
    :header-cell-style="{backgroundColor:'#F6F8F9',color:'#333',textAlign:'center'}" 要求1、折线为渐变色2、折线区域渐变色3、x轴y轴不展示 4、折线图背景为网格   5、鼠标划上样式修改 constoption={title:{......
  • OpenMesh 计算网格顶点Voronoi面积
    文章目录一、简介二、实现代码三、实现代码参考资料一、简介在计算离散的微分算子时(如拉普拉斯算子、高斯曲率等),总是会需要计算某个网格顶点的局部面积,主要有以下几种:该操作类似于点云中的邻域操作,只不过点云的邻域一般是基于一个圆或者一个圆柱,而这里则......
  • 布局升级秘籍:掌握CSS Grid网格布局,打造响应式网页设计
    随着现代网页设计的不断演进,传统的布局方式已经逐渐不能满足设计师和开发者们对于高效、灵活且强大布局系统的追求。而CSSGrid网格布局,正是在这样的背景下应运而生的。今天,我们就来深入探讨CSSGrid布局的魅力所在,带你解锁这项强大的设计工具,让网页布局变得更加简单和高效。......
  • 如何在您的网页项目中使用便当网格设计
    我相信我们都可能注意到了精心组织的网页布局的趋势,让人联想起日本便当盒。这些“便当网格”迅速赢得了关注,提供了一种视觉上吸引人且结构紧凑的方式来在线展示内容。在本文中,我们将深入探讨便当网格趋势的起源、崛起和实际应用,探讨它如何在现代网页设计中将美学与功能相结合。(......
  • 2617. 网格图中最少访问的格子数(困难)
    核心思想比较直观的想法就是BFS,但是每次遍历能走的点(右走,下走)会超时考虑用两个set数组,TreeSet<Integer>[]R=newTreeSet[n];TreeSet<Integer>[]C=newTreeSet[m];R[i]表示第i行还剩下哪些列col没去过,那么遍历就变为了二分查找第一个比当前j大的col当col>......
  • 56文章解读与程序——论文可下载-基于微网格形成的弹性配电系统新模型-----已提供下载
    ......
  • 前端学习-UI框架学习-Bootstrap5-003-网格系统
    菜鸟教程链接Bootstrap提供了一套响应式、移动设备优先的流式网格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列规则网格每一行需要放在设置了.container(固定宽度)或.container-fluid(全屏宽度)类的容器中,这样就可以自动设置一些外边距与内边距。使......