Petrozavodsk Programming Camp, Winter 2021 Day 1 Problem H
发现操作是可逆的,如果起始状态和终止状态都能走到同一个状态,那就能组合出一组解。
以任意一节点为根,考虑贪心地确定每个人最后的位置,使他对答案影响最小。策略是将可以放的人放到深度最大的点,然后删掉该点相邻的点,反复去做。
大多数情况下,总有一种方式使得一个节点能走到当前选择的深度最大点,但是有唯一一种情况不行——存在两个儿子上有人,互相卡住对方。此时,可以证明,如果将所有的点都往当前点的反方向能走一步就走一步,如果有解就一定能消除这样的情况。
#include <bits/stdc++.h>
using namespace std;
namespace FastIO {
struct IO {
char ibuf[(1 << 20) + 1], *iS, *iT, obuf[(1 << 20) + 1], *oS;
IO() : iS(ibuf), iT(ibuf), oS(obuf) {} ~IO() { fwrite(obuf, 1, oS - obuf, stdout); }
#if ONLINE_JUDGE
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
#else
#define gh() getchar()
#endif
inline bool eof (const char &ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == 't' || ch == EOF; }
inline long long read() {
char ch = gh();
long long x = 0;
bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
return t ? ~(x - 1) : x;
}
inline void read (char *s) {
char ch = gh(); int l = 0;
while (eof(ch)) ch = gh();
while (!eof(ch)) s[l++] = ch, ch = gh();
}
inline void read (double &x) {
char ch = gh(); bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = x * 10 + (ch ^ 48), ch = gh();
if (ch != '.') return t && (x = -x), void(); ch = gh();
for (double cf = 0.1; '0' <= ch && ch <= '9'; ch = gh(), cf *= 0.1) x += cf * (ch ^ 48);
t && (x = -x);
}
inline void pc (char ch) {
#ifdef ONLINE_JUDGE
if (oS == obuf + (1 << 20) + 1) fwrite(obuf, 1, oS - obuf, stdout), oS = obuf;
*oS++ = ch;
#else
putchar(ch);
#endif
}
template<typename _Tp>
inline void write (_Tp x) {
static char stk[64], *tp = stk;
if (x < 0) x = ~(x - 1), pc('-');
do *tp++ = x % 10, x /= 10;
while (x);
while (tp != stk) pc((*--tp) | 48);
}
inline void write (char *s) {
int n = strlen(s);
for (int i = 0; i < n; i++) pc(s[i]);
}
} io;
inline long long read () { return io.read(); }
template<typename Tp>
inline void read (Tp &x) { io.read(x); }
template<typename _Tp>
inline void write (_Tp x) { io.write(x); }
}
using namespace FastIO;
const int maxn=1e5+10;
int n,k,a[maxn],b[maxn],tz1[maxn],tz2[maxn],dep[maxn],p[maxn],ct[maxn];
vector<int> G[maxn];
vector< pair<int,int> > SA,SB;
void predfs(int u,int fa)
{
dep[u]=dep[fa]+1;
for(int v:G[u])
if(v!=fa)
predfs(v,u);
}
bool spindfs(int u,int fa,int *d,int *c,vector< pair<int,int> > &A)
{
int flag=0,cm=0,cnt=0;
for(int v:G[u])
if(v!=fa)
{
if(d[v]&&c[v])flag=1;
if(d[v]&&!c[v])cm=v,cnt++;
}
if(flag)return 0;
if(cnt==1)
{
A.emplace_back(cm,u);
//rintf("@%d %d\n",cm,u);
swap(d[u],d[cm]);
return 1;
}
if(!cnt)
{
for(int v:G[u])
if(v!=fa&&spindfs(v,u,d,c,A))
{
// printf("#%d %d\n",v,u);
A.emplace_back(v,u);
swap(d[v],d[u]);
return 1;
}
}
return 0;
}//将任意节点旋到深度最大的点
int levdfs(int u,int fa,int *d,int *c,vector< pair<int,int> > &A)
{
if(d[u])
{
if(c[u])return 0;
for(int v:G[u])
if(v!=fa&&levdfs(v,u,d,c,A)>=2)
{
// printf("?%d %d\n",u,v);
A.emplace_back(u,v);
swap(d[u],d[v]);
return 1;
}
return 0;
}
else
{
int mn=1e9;
for(int v:G[u])
if(v!=fa)
mn=min(mn,levdfs(v,u,d,c,A)+1);
return mn;
}
}//将卡住路径的节点拉远
void solve()
{
n=read();
SA.clear();SB.clear();
for(int i=1;i<=n;i++)G[i].clear(),tz1[i]=tz2[i]=ct[i]=0;
for(int i=1,u,v;i<n;i++)
{
u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
k=read();
for(int i=1;i<=k;i++)
a[i]=read(),tz1[a[i]]=1;
for(int i=1;i<=k;i++)
b[i]=read(),tz2[b[i]]=1;
predfs(1,0);for(int i=1;i<=n;i++)p[i]=i;sort(p+1,p+1+n,[&](int a,int b){return dep[a]>dep[b];});
for(int i=1;i<=n;i++)
{
int u=p[i];
if(!tz1[u])levdfs(u,0,tz1,ct,SA),spindfs(u,0,tz1,ct,SA);
if(!tz2[u])levdfs(u,0,tz2,ct,SB),spindfs(u,0,tz2,ct,SB);
ct[u]=1;
}
for(int i=1;i<=n;i++)if(tz1[i]!=tz2[i])
{
puts("NO");
return;
}
puts("YES");
printf("%d\n",SA.size()+SB.size());
for(auto [u,v]:SA)printf("%d %d\n",u,v);
reverse(SB.begin(),SB.end());
for(auto [u,v]:SB)printf("%d %d\n",v,u);
return;
}
int main()
{
int T;
scanf("%d\n",&T);
while(T--)solve();
return 0;
}
本文作者:_kkio
本文链接:https://www.cnblogs.com/hikkio/p/17686515.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步