Petrozavodsk Programming Camp, Winter 2021 Day 1 Problem H

发布时间 2023-09-08 07:57:14作者: _kkio

发现操作是可逆的,如果起始状态和终止状态都能走到同一个状态,那就能组合出一组解。

以任意一节点为根,考虑贪心地确定每个人最后的位置,使他对答案影响最小。策略是将可以放的人放到深度最大的点,然后删掉该点相邻的点,反复去做。

大多数情况下,总有一种方式使得一个节点能走到当前选择的深度最大点,但是有唯一一种情况不行——存在两个儿子上有人,互相卡住对方。此时,可以证明,如果将所有的点都往当前点的反方向能走一步就走一步,如果有解就一定能消除这样的情况。

#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;
}