Tokens on Graph
感觉是比较好想的。
考虑对于每个点判断从这个点出发能不能到达 号点。能到达的必要条件是存在一条从这个点到 的路径,其上除了这个点和 号点外的所有点都是特殊点。
但这个条件并不充分。由于每到一个特殊点,我们要移动一个其他棋子,所以我们必然想让这条路径尽量短。容易广搜在 的复杂度内处理这个东西。
接着我们考虑其他棋子的贡献。分为四种:
-
存在一个点上有棋子,且这个点是特殊点,与其相邻的点中有至少一个特殊点。这种情况下,来回走,就可以无限地贡献。
-
存在一个点上有棋子,这个点不是特殊点,但这个点相邻的点中有至少一个点在大小不小于 地特殊点连通块中。容易发现也是无限贡献。
-
这个点相邻地点只有大小为 地连通块,贡献为这个点棋子数量,显然,由于每个点只能出去一次,且回不来。
-
这个点相邻点中没有特殊点。贡献为 。
上述分类都容易计算,于是做完了。
#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;
}