Tokens on Graph

感觉是比较好想的。

考虑对于每个点判断从这个点出发能不能到达 11 号点。能到达的必要条件是存在一条从这个点到 11 的路径,其上除了这个点和 11 号点外的所有点都是特殊点。

但这个条件并不充分。由于每到一个特殊点,我们要移动一个其他棋子,所以我们必然想让这条路径尽量短。容易广搜在 O(n+m)O(n+m) 的复杂度内处理这个东西。

接着我们考虑其他棋子的贡献。分为四种:

  1. 存在一个点上有棋子,且这个点是特殊点,与其相邻的点中有至少一个特殊点。这种情况下,来回走,就可以无限地贡献。

  2. 存在一个点上有棋子,这个点不是特殊点,但这个点相邻的点中有至少一个点在大小不小于 22 地特殊点连通块中。容易发现也是无限贡献。

  3. 这个点相邻地点只有大小为 11 地连通块,贡献为这个点棋子数量,显然,由于每个点只能出去一次,且回不来。

  4. 这个点相邻点中没有特殊点。贡献为 00

上述分类都容易计算,于是做完了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <string>
#include <vector>
using namespace std;
 // 111321443123
const int N = 2e5 + 5;

int t, n, p, b, m;
vector<int> G[N];
bool is[N];
int c[N];
int dis[N];

void bfs()
{
	queue<int> q;
	q.push(1);
	for (int i = 2; i <= n; i++) dis[i] = -1;
	dis[1] = 0;
	while (q.size())
	{
		int u = q.front();
		q.pop();
		for (auto& j : G[u])
		{
			if (dis[j] == -1)
			{
				dis[j] = dis[u] + 1;
				if (is[j]) q.push(j);
			}
		}
	}
}

int cc[N];

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> n >> m >> p >> b;
		for (int i = 1; i <= n; i++)
		{
			cc[i] = 0;
			G[i].clear();
			is[i] = 0;
			c[i] = 0;
		}
		for (int i = 1; i <= p; i++)
		{
			int x;
			cin >> x;
			c[x]++;
		}
		for (int i = 1; i <= b; i++)
		{
			int x;
			cin >> x;
			is[x] = 1;
		}
		for (int i = 1; i <= m; i++)
		{
			int u, v;
			cin >> u >> v;
			G[u].emplace_back(v);
			G[v].emplace_back(u);
		}
		for (int i = 1; i <= n; i++)
		{
			for (auto& j : G[i])
			{
				if (is[j]) cc[i]++;
			}
		}
		bfs();
		long long nowres = 0;
		for (int i = 1; i <= n; i++)
		{
			if (is[i] && cc[i])
			{
				nowres += N * 1LL * c[i];
			}
			else if (cc[i])
			{
				bool f = 0;
				for (auto& j : G[i])
				{
					if (is[j])
					{
						int nc = cc[j] - (is[i]);
						if (nc > 0)
						{
							f = 1;
						}
					}
				}
				if (f) nowres += N * 1LL * c[i];
				else nowres += c[i];
			}
		}
		if (c[1] > 0) cout << "YES\n";
		else
		{
			bool ff = 0;
			for (int i = 2; i <= n; i++)
			{
				if (dis[i] == -1 || !c[i]) continue;
				int g = dis[i] - 1;
				long long nres = nowres;
				if (is[i] && cc[i])
				{
					nres -= N * 1LL;
				}
				else if (cc[i])
				{
					bool f = 0;
					for (auto& j : G[i])
					{
						if (is[j])
						{
							int nc = cc[j] - (is[i]);
							if (nc > 0)
							{
								f = 1;
							}
						}
					}
					if (f) nres -= N * 1LL;
					else nres--;
				}
				if (nres >= g)
				{
					ff = 1;
					//cout << i << " " <<
				}
			}
			if (ff) cout << "YES\n";
			else cout << "NO\n";
		}
	}
	return 0;
}
posted @ 2023-08-25 19:31  HappyBobb  阅读(6)  评论(0编辑  收藏  举报  来源