很明显一点,T1树里每一条边都会被选取一次。把T2树的每一条边看成一个线段覆盖。每次找到一个只被覆盖了一次的线段,找到他是被那个区间覆盖的,把那个区间删去。如果最后能删完,就有解,删不完就是无解。
搞个树剖维护区间被覆盖的最小次数。但是较难的地方是:如何判断某一条边是被那个区间覆盖的。其实我们可以再维护一个值,把覆盖这个点的区间的编号加起来,因为我们找线段时只是找被覆盖一次的线段,所以一定就是他的编号了。因此在删区间的时候,额外维护这个变量。
另一个比较难的地方:找到你要删的那条边后,把它赋成inf,他就不会对答案产生影响了(维护的是区间最小值,0可是比1小的。。),我曾经卡在一个地方,就是在删区间时删出来一个0怎么办。那么这个0一定不会再被那一个区间选择了。但是很明显每条边都是要被选的,那这就一定无解了。
注:把边权下放到点时注意把用不到的点赋成无限大。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define N 200005
#define inf 1000000000
#define mem(x) (memset(x,0,sizeof(x)))
#define ll long long
using namespace std;
struct road{int v,next;}lu[N*2];
struct node{int x,y;}a[N];
int T,ans,n,e,cnt,adj[N],f[N],top[N],sz[N],son[N],id[N],dep[N];
void add(int u,int v){lu[++e]=(road){v,adj[u]};adj[u]=e;}
namespace TREE
{
struct tree{int l,r,su,lsu;ll h,lh;}t[N*4];
inline void build(int l,int r,int x)
{
t[x].l=l;t[x].r=r;
t[x].h=t[x].lh=t[x].lsu=t[x].su=0;
if(l==r)return;
int mid=l+r>>1;
build(l,mid,x*2);
build(mid+1,r,x*2+1);
}
inline void down(int x)
{
int h=t[x].lh,su=t[x].lsu;
t[x].lh=t[x].lsu=0;
t[x*2].h+=h;t[x*2].lh+=h;
t[x*2+1].h+=h;t[x*2+1].lh+=h;
t[x*2].su+=su;t[x*2].lsu+=su;
t[x*2+1].su+=su;t[x*2+1].lsu+=su;
}
inline void Q(int x)
{
if(t[x].l==t[x].r){ans=t[x].h,t[x].su=inf;return;}
if(t[x].lh)down(x);
if(t[x*2].su==1)Q(x*2);
else Q(x*2+1);
t[x].su=min(t[x*2].su,t[x*2+1].su);
}
inline void add(int l,int r,int k,ll h,int x)
{
if(t[x].l>=l&&t[x].r<=r)
{
t[x].su+=k;t[x].lsu+=k;
t[x].h+=h;t[x].lh+=h;
if(l==1)t[x].su=inf;
return;
}
if(t[x].lh)down(x);
int mid=t[x].l+t[x].r>>1;
if(l<=mid)add(l,r,k,h,x*2);
if(r>mid)add(l,r,k,h,x*2+1);
t[x].su=min(t[x*2].su,t[x*2+1].su);
}
inline void C(int x,int y,int k,ll h)
{
int fx=top[x],fy=top[y];
while(fx^fy)
{
if(dep[fx]<dep[fy])swap(fx,fy),swap(x,y);
add(id[fx],id[x],k,h,1);
x=f[fx],fx=top[x];
}
if(x==y)return;
if(id[x]>id[y])swap(x,y);
add(id[x]+1,id[y],k,h,1);
}
}
using namespace TREE;
inline void dfs1(int x,int fa)
{
f[x]=fa;sz[x]=1;dep[x]=dep[fa]+1;
for(int i=adj[x];i;i=lu[i].next)
{
int to=lu[i].v;if(to==fa)continue;
dfs1(to,x);sz[x]+=sz[to];
if(sz[to]>sz[son[x]])son[x]=to;
}
}
inline void dfs2(int x,int y)
{
top[x]=y;id[x]=++cnt;
if(!son[x])return;
dfs2(son[x],y);
for(int i=adj[x];i;i=lu[i].next)
{
int to=lu[i].v;
if(to==f[x]||to==son[x])continue;
dfs2(to,to);
}
}
bool check()
{
dfs1(1,0);dfs2(1,1);build(1,n,1);add(1,1,1,inf,1);
for(int i=1;i<n;i++)C(a[i].x,a[i].y,1,i);
for(int i=1;i<n;i++)
{
if(t[1].su!=1)return 0;
ans=0;Q(1);
C(a[ans].x,a[ans].y,-1,-ans);
}
return 1;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);e=cnt=0;
mem(sz);mem(son);mem(f);mem(top);mem(adj);mem(dep);mem(id);
for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),a[i]=(node){x,y};
if(check())printf("YES\n");
else printf("NO\n");
}
}