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 = \frac{a + b}{2}
如果不存在就输出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>