其他分享
首页 > 其他分享> > NOI 2016 题目选做

NOI 2016 题目选做

作者:互联网

网格

题目描述

点此看题

解法

首先有一个关键的 \(\tt observation\):答案不会超过 \(2\)(可以直接封锁边界点),那么根据众多 \(\tt CF\) 题目的经验,我们可以直接开始分类讨论:

那么暴力建图可以做到 \(O(nm)\) 的复杂度,一个比较显然的思路是保留每个障碍旁边的若干点,虽然貌似这种做法可以通过官方数据但是很容易被 \(\tt hack\),这里介绍一种不需要特判的优化建图方法,首先我们保留这些点:

那么对于保留的点,如果两个点在同一行或者同一列并且中间没有障碍物,就连一条边。最后暴力 \(\tt tarjan\) 求割点即可,时间复杂度 \(O(c)\)

正确性证明待补充。

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 10000005;
#define pb push_back
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,n,m,c,q,t,cnt,zxy,dfn[M],low[M];
vector<int> g[M];
struct node {int x,y,t;}a[M];
bool cmp1(node a,node b)
{
	if(a.x==b.x && a.y==b.y) return a.t<b.t;
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(node a,node b)
{
	return a.y==b.y?a.x<b.x:a.y<b.y;
}
void add(int x,int y,int dx,int dy)
{
	for(int i=-dx;i<=dx;i++)
		for(int j=-dy;j<=dy;j++)
		{
			int tx=x+i,ty=y+j;
			if(tx>=1 && tx<=n && ty>=1 && ty<=m)
				a[++t]={tx,ty,0};
		}
}
void dfs(int u,int fa)
{
	dfn[u]=low[u]=++cnt;int son=0;
	for(int v:g[u])
	{
		if(!dfn[v])
		{
			dfs(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
				if(fa) zxy=1;
				else son++;
			}
		}
		else if(v!=fa) low[u]=min(low[u],dfn[v]); 
	}
	if(son>1) zxy=1;
}
void work()
{
	n=read();m=read();c=read();q=t=0;
	for(int i=1;i<=c;i++)
	{
		int x=read(),y=read();
		add(x,y,1,1);
		add(1,y,0,0);add(n,y,0,0);
		add(x,1,0,0);add(x,m,0,0);
		a[++t]={x,y,-1};
	}
	add(1,1,2,2);add(1,m,2,2);add(n,1,2,2);add(n,m,2,2);
	sort(a+1,a+1+t,cmp1);int pt=0;node ls;
	for(int i=1;i<=t;i++)
		if(ls.x!=a[i].x || ls.y!=a[i].y)
			ls=a[i],a[++pt]=ls;
	t=pt;cnt=zxy=0;
	for(int i=1;i<=t;i++)
		if(a[i].t!=-1) a[i].t=++q;
	for(int i=1;i<=q;i++)
		dfn[i]=low[i]=0,g[i].clear();
	for(int i=2;i<=t;i++)
		if(a[i].x==a[i-1].x && a[i].t!=-1 && a[i-1].t!=-1)
			g[a[i].t].pb(a[i-1].t),g[a[i-1].t].pb(a[i].t);
	sort(a+1,a+1+t,cmp2);
	for(int i=2;i<=t;i++)
		if(a[i].y==a[i-1].y && a[i].t!=-1 && a[i-1].t!=-1)
			g[a[i].t].pb(a[i-1].t),g[a[i-1].t].pb(a[i].t);
	if(q<=1 || (q<=2 && !g[1].empty()))
	{
		puts("-1");
		return ;
	}
	dfs(1,0);
	if(cnt<q) puts("0");
	else puts(zxy?"1":"2");
}
signed main()
{
	T=read();
	while(T--) work();
}

标签:选做,NOI,int,tt,read,include,&&,2016,跳蚤
来源: https://www.cnblogs.com/C202044zxy/p/16209723.html