D. D/D/D
链接
https://codeforces.com/problemset/problem/2109/D
题目大意
给定无重边无自环、n点m边图,一个集合A,取A中的元素组合得到新数y,使得从1出发能花费y步达到x号节点。如果能达到x号节点输出1,否则输出0。
思路
显然,若x步能达到,那么x+2*n(n∈N)步也能达到,那么对每个节点维护最短奇、偶步,考虑A中的最大奇、偶步骤,如果大于等于那么就输出1。
每个节点至多遍历2次,时间复杂度O(n)。
代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
#define tin long long
#define itn long long
using namespace std;
int t,n,m,l;
const int N = 2e5 + 10;
int odd[N], even[N];
bool vis[N];
int a[N];
int suma;
int aminodd, amineven;
vector<int>G[N];
struct ele
{
int to, val;
ele(){}
ele(int toa, int vala) { to = toa, val = vala; }
};
void init()
{
suma = 0;
amineven = aminodd = LLONG_MAX;//初始化
for (int i = 1; i <= n; i++)G[i].clear(),a[i]=0;
for (int i = 1; i <= n; i++)vis[i] = false, odd[i] = even[i] = -1;//和0区分
}
void input()
{
cin >> n >> m >> l;
init();
for (int i = 1; i <= l; i++)cin >> a[i];
for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); }
}
void solve()
{
for (int i = 1; i <= l; i++) { suma += a[i]; if (a[i] % 2)aminodd = min(aminodd, a[i]); else amineven = min(amineven, a[i]); }
sort(a + 1, a + 1 + l);
queue<ele>q;
q.push(ele(1, 0));
while (!q.empty())
{
ele now = q.front(); q.pop();
int u = now.to, val = now.val;
vis[u] = true;
if (val % 2)odd[u] = val;
else even[u] = val;
for (int v : G[u])
{
if (vis[v])
{
if (odd[v] == -1 and (val + 1) % 2) { odd[v] = val + 1;q.push(ele(v, val + 1)); }//绕一圈走到下一个节点的情况,更新
else if (even[v] == -1 and (val + 1) % 2 == 0) { even[v] = val + 1;q.push(ele(v, val + 1)); }
}
else q.push(ele(v, val + 1));
}
}
even[1] = 0;
bool bef = false;
int sumanex = -1;
if (aminodd != LLONG_MAX) sumanex = suma - aminodd;
if (suma % 2)swap(suma, sumanex);//suma even
for (itn i = 1; i <= n; i++)
{
if ((suma >= even[i] and even[i] != -1) or (sumanex!=-1 and sumanex >= odd[i] and odd[i]!=-1))cout << 1;
else cout << 0;
}
cout << '\n';
}
signed main()
{
IOS;
cin >> t;
while (t--) {input(); solve(); }
return 0;
}