Codeforces 847 Div3 题解A-G

Posted tiany7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 847 Div3 题解A-G相关的知识,希望对你有一定的参考价值。

Codeforces 847 Div3 题解A-G

好久不打了,这几周忙着写各种作业,然后发现代码力跟不上了。今天复健一下吧。反正也是比较碎片的时间,马上新的作业就会被布置下来,n久没打了就来看下。所以这次先捡div3复键一下,之后暑假等实习了到时候得认真上上div2,不然秋招g咯。

A. Polycarp and the Day of Pi

这个题题意给出一个1-30位string,问猜圆周率的人猜对了几位

这个本来想用acos(-1)按照位进行比对,后来发现题目中给了圆周率的前30位,那这题就是白送了。

AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
void solve()
	string str;
	cin>>str;
	n = str.length();
	str = " " + str;
	string num = " 314159265358979323846264338327";
	rep(i,1,n)
		int x = str[i] - \'0\';
		if(str[i] != num[i])
			cout<<i-1<<endl;
			return;
		
	
	cout<<n<<endl;
;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;


B. Taisia and Dice

这个题题意是给出一个n个骰子的序列,然后我们知道筛子上面的总和是s,然后去掉最大的那个总和是r,要求给出一种序列构造。

这个题就是贪心,懒得讲了,直接看代码。

AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
void solve()
	int s,r;
	cin>>n>>s>>r;
	a[1] = s - r;//现在的
	int rem = s - (n - 1) - a[1];
	rep(i,2,n)
		int minn = max(0, min(rem,  a[1] - 1));
		a[i] = 1 + minn;
		rem -= minn;
	
	per(i,1,n)
		cout<<a[i]<<" ";
	
	cout<<endl;
;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;

    

C. Premutation

这题题意是,我们有个permutation,然后我们操作n次,第i次遮住第i个数字,然后所有操作序列给出,但是未必是按照顺序来的,要求我们复原这个permutation。

这个题看样例,我们发现第一列必然只有一个数字出现了1次,而且每一列有且只有两个数字,那么我们想一下就会发现两件事

  • 第一列只出现一次的数字是permutation的第二个数字, 出现n-1次的数字是permutation的第一个数字
  • 我们可以通过一列数字来推出当前和接下来一位总共两位数字

这个性质是有传递性的,也就是说我们可以通过前两列来推出第三列,第三列来推出第四列,以此类推。

接下来就很简单了,我手太生了,写锅了好几次,不过最后还是写出来了。

AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
int mp[105][105];
void solve()
	cin>>n;
	rep(i,1,n)
		rep(j, 1, n - 1)
			cin>>mp[i][j];
		
	
	set<int>s;
	rep(i,1,n)
		s.insert(i);
	
	map<int, int>mpp;
	rep(i,1,n)
		mpp[mp[i][1]]++;
	
	int now = -1;
	int last;
	for(auto [k, v]: mpp)
//		cout<<k<<" "<<v<<endl;
		if(v == 1)
			now = k;
		else
			last = k;
		
	
	a[1] = last;
	s.extract(last);
	int tot = 2;
	int next = now;
	rep(j,2,n - 1)
		int res = 0;
		rep(i,1,n)
			if(mp[i][j] != next) //如果现在还不是下一个
				res = mp[i][j];

			else
				a[tot] = mp[i][j];
			
		
		s.extract(a[tot++]);
		next = res;
	
	if(s.size())
		a[n] = *s.begin();
	
	rep(i,1,n)
		cout<<a[i]<<" ";
	
	cout<<endl;
;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;


D. Matryoshkas

这个题问你,给出n个数字,要求我们拆解成尽可能少的公差为1的等差数列,第一项随意,然后输出最少能拆成几个。

这个题首先暴力是没法划分的(显然)。我甚至想到了网络流,刚准备建图,但总觉得有更简单的做法。考虑一下之后,发现我们可以从出现次数最少的入手,那么我们每次连续删除以当前出现次数最少的数字为中心(其实这个说法不准确,应该是包含这个数字的连续序列),贪心地向两边扩展,直到遇到第一个没出现的数字为止。我们用map记录下数字的出现次数。最后操作总数一定是bound在O(N)的,复杂度也就是O(NlogN)了。

AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
struct node
	int val, cnt;
	bool operator < (const node &rhs) const
		return val < rhs.val;
	
;
void solve()
	cin>>n;
	rep(i,1,n)
		cin>>a[i];
	
	sort(a + 1, a + 1 + n);
	int ans = 0;
	map<int, int>mp;
	for_each(a + 1, a + 1 + n, [&](int x)mp[x]++;);
	vector<node>v;
	for(auto [k, vv] : mp)
		v.push_back(vv, k);
	
	sort(v.begin(), v.end());
	for(auto [cnt, num] : v)
		rep(_, 1, cnt)
			if(!mp[num])continue;
			per(i,1,num)
				if(!mp[i])
					break;
				
				mp[i]--;
			
			rep(i, num + 1, 1e12)
				if(!mp[i])
					break;
				
				mp[i]--;
			
			++ans;
		
	
	cout<<ans<<endl;

;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;


E. Vlad and a Pair of Numbers

这个题是给出来a + b的和,要求找出来a和b使得

a \\oplus b = \\fraca + b2

如果不存在就输出1.

首先我们反向思维一下,这题的本质是a + b异或,然后右移一位。

首先我们可以确定,因为右移的关系,替换到左边就是左移,所以这个\\(a \\oplus b\\)的值一定是偶数。

然后我们考虑一下i和i - 1位置上之间的关系,如果\\(a \\oplus b\\)的值在第i位是1,那么只能说明一个问题,就是当前位置上是1和0(分别),那么如果这一位是这样,前一位的就不能是1,因为这样就会导致异或的结果是奇数,所以我们可以得到二个结论,就是如果\\(a \\oplus b\\)的值在第i位是1,那么第i - 1位a和b一定都是1,否则答案就不存在。

然后上代码

AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
struct node
	int val, cnt;
	bool operator < (const node &rhs) const
		return val < rhs.val;
	
;
void solve()
	cin>>n;
	rep(i,1,n)
		cin>>a[i];
	
	sort(a + 1, a + 1 + n);
	int ans = 0;
	map<int, int>mp;
	for_each(a + 1, a + 1 + n, [&](int x)mp[x]++;);
	vector<node>v;
	for(auto [k, vv] : mp)
		v.push_back(vv, k);
	
	sort(v.begin(), v.end());
	for(auto [cnt, num] : v)
		rep(_, 1, cnt)
			if(!mp[num])continue;
			per(i,1,num)
				if(!mp[i])
					break;
				
				mp[i]--;
			
			rep(i, num + 1, 1e12)
				if(!mp[i])
					break;
				
				mp[i]--;
			
			++ans;
		
	
	cout<<ans<<endl;

;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;


F. Timofey and Black-White Tree

这题真不会,是vp结束之后看jiangly代码写的,这题本质是有根树,每次把节点涂黑,问黑节点当中距离最小的值是多少。

我之前想的是用lca,维护lca群,然后每次更新的时候分为两种情况,一种是lca在底下,那么记录一下lca下面离得最近的黑色节点,然后更新ans,另一种是lca在上面,那么就把lca的父亲节点的最近的黑色节点更新一下,然后更新ans,再把所有淘汰的节点从里面pop掉,重构lca群。

听上去很无敌,但是读了下题发现是有根树,那就不行了。

赛后看的是,应该是简单的bfs,用贪心去收集答案,在bfs的时候每次只有答案小于当前的最小值才更新,复杂度\\(O(n\\sqrt n)\\)

然后上代码

AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
vector<int>g[limit];
int c[limit];
int fa[limit];
int find(int x)
	return x == fa[x] ? x : fa[x] = find(fa[x]);

void merge(int x,int y)
	int fx = find(x);
	int fy = find(y);
	if(fx != fy)
		fa[fx] = fy;
	

int sizes[limit], pre[limit], son[limit], dep[limit], top[limit], dfn[limit], tot;
void dfs1(int u, int f, int d) 
	dep[u] = d;
	sizes[u] = 1;
	pre[u] = f;
	for (auto v : g[u]) 
		if (v == f)continue;
		dfs1(v, u, d + 1);
		sizes[u] += sizes[v];
		if (sizes[v] > sizes[son[u]])son[u] = v;
	

void dfs2(int u, int t) 
	dfn[u] = ++tot;
	top[u] = t;
	if (son[u])dfs2(son[u], t);
	for (auto v : g[u]) 
		if (v == pre[u] || v == son[u])continue;
		dfs2(v, v);
	

int lca(int x, int y) 
	while (top[x] != top[y]) 
		if (dep[top[x]] < dep[top[y]])swap(x, y);
		x = pre[top[x]];
	
	return dep[x] < dep[y] ? x : y;

int dis(int x, int y) 
	return dep[x] + dep[y] - 2 * dep[lca(x, y)];

int dist[limit];
void solve()
	cin>>n>>c[1];
	rep(i,1,n)
		g[i].clear();
		fa[i] = i;\\
		dist[i] = numeric_limits<int>::max();
	
	rep(i,2,n)
		cin>>c[i];
	
	rep(i,1,n - 1)
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	
	int ans = INF;
	auto bfs = [&](int x)
		queue<int>q;
		q.push(x);
		dist[x] = 0;
		while(!q.empty())
			int u = q.front();
			q.pop();
			for(auto v : g[u])
				if(dist[v] > dist[u] + 1 and dist[u] + 1 < ans )
					dist[v] = dist[u] + 1;
					q.push(v);
				
			
		
	;
	bfs(c[1]);
	rep(i,2,n)
		a[i] = ans = min(ans,dist[c[i]]);
		bfs(c[i]);
	
	rep(i,2,n)
		cout<<a[i]<<\' \';
	
	cout<<endl;
;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;

G. Tokens on Graph

这个题是给了一些token和一个无向图,我们的任务是把一个token移动到编号为1的节点上去。然后有一些bonus节点,没有使用次数和流量限制,但是我们不能连续移动一个token,而且我们每次需要把节点上的token移动到bonus节点上去才能继续走下一次。问给出一个构造图,能不能在一轮游戏中把一个token移动到编号为1的节点上去。

我卡在F了一会儿,发现关注的人都去做G了,所以我也来看G。

这道题我们发现,首先需要有至少一个token,其通往节点1的路径最短,且途中必须全部由bonus节点组成。我们有若干个token,把这个token拿掉,继续看其他token,所以每个token可以移动1次或者无数次(因为没有使用次数限制,如果路上有两个bonus节点就back and forth就好了),如果不存在无数次的,那么我们看看选中最短路的费用 - 1是否可以由其他只能move一次的token抵消掉.如果可以,那么yes,否则no

然后wa了,发现我们在统计步长为1的链的时候,对答案贡献最多为一次,改了就过了

AC代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (4e5  + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read() 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > \'9\' || s < \'0\') 
        if (s == \'-\')sign = -1;
        s = getchar();
    
    while (s >= \'0\' && s <= \'9\') 
        x = (x << 3) + (x << 1) + s - \'0\';
        s = getchar();
    
    return x * sign;
#undef getchar
//快读
void print(ll x) 
    if (x / 10) print(x / 10);
    *O++ = x % 10 + \'0\';


void write(ll x, char c = \'t\') 
    if (x < 0)putchar(\'-\'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;



int n,m;
int a[limit];
vector<int> g[limit], g2[limit];
int token[limit];
int bonus[limit];
int fa[limit];
int vis[limit];
int find(int x)
	return fa[x] == x ? x : fa[x] = find(fa[x]);

void merge(int x,int y)
	int fx = find(x);
	int fy = find(y);
	if(fx != fy)
		if(fx > fy)swap(fx,fy);
		fa[fx] = fy;
	

void solve()
	int p, b;
	cin>>n>>m;
	cin>>p>>b;
	rep(i,1,n)
		fa[i] = i;
	
	rep(i,1,p)
		cin>>token[i];
	
	rep(i,1,b)
		cin>>bonus[i];
	
	sort(token + 1,token + 1 + p);
	sort(bonus + 1,bonus + 1 + b);
	rep(i,1,n)
		g[i].clear();
		vis[i] = 0;
	
	rep(i,1,m)
		int u,v;
		cin>>u>>v;
		if(u != 1 and !binary_search(token + 1,token + 1 + p,u) and !binary_search(bonus + 1,bonus + 1 + b,u))
			continue;
		
		if(v != 1 and !binary_search(token + 1,token + 1 + p,v) and !binary_search(bonus + 1,bonus + 1 + b,v))
			continue;
		
		g[u].push_back(v);
		g[v].push_back(u);
	
	if(binary_search(token + 1,token + 1 + p,1))
		cout<<"Yes"<<endl;
		return;
	
	auto [rt, cost] = [&]()->pi(int, int)
		queue<pi(int, int)>q;
		q.push(1, 0);
		vis[1] = 1;
		while(!q.empty())
			auto [u, c] = q.front();
			q.pop();
			if(binary_search(token + 1,token + 1 + p,u))
				return u, c;
			
			for(auto v : g[u])
				if(!vis[v])
					vis[v] = 1;
					q.push(v, c + 1);
				
			
		
		return 0, 0;
	();
//	cout<<rt<<" "<<cost<<endl;
	if(!rt)
		cout<<"No"<<endl;
		return;
	

	int big = 0, small = 0;//分别代表反复横跳和直接跳到的次数
	rep(i,1,p)
		int res = 0;
		if(token[i] == rt)continue;
		queue<pi(int, int)>q;
		q.push(token[i], 0);
		while(q.size())
			auto [u, c] = q.front();
			q.pop();
			if(c == 2)
				res--;
				big = 1;
				break;
			
			if(c == 1)
				res++;
			
			for(auto v : g[u])
				if(binary_search(bonus + 1,bonus + 1 + b,v))
					q.push(v, c + 1);
			
		
		if(res > 0)
			small++;
		
	
//	cout<<big<<" "<<small<<endl;
	if(big)
		cout<<"Yes"<<endl;
		return;
	
	if(small >= cost - 1)
		cout<<"Yes"<<endl;
		return;
	
	cout<<"No"<<endl;
;
int32_t main() 
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        invoke(solve);
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
    return 0;

<\\details>

Codeforces Round #815 (Div. 2) 题解

Codeforces Round #815 (Div. 2) 全场题解
Codeforces Round #815 (Div. 2) 全场题解

以上是关于Codeforces 847 Div3 题解A-G的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #719 (Div. 3) A-G题解 G题详细注释

Codeforces Round #719 (Div. 3) A-G题解 G题详细注释

Codeforces Round #725 (Div. 3) 题解(A-G)

Codeforces Round #719 (Div. 3) A-G 题解

codeforces #595 div3 题解

Codeforces Round #617(div3) A-E2题解