树链剖分 树
、
很明显一点,T1树里每一条边都会被选取一次。把T2树的每一条边看成一个线段覆盖。每次找到一个只被覆盖了一次的线段,找到他是被那个区间覆盖的,把那个区间删去。如果最后能删完,就有解,删不完就是无解。
搞个树剖维护区间被覆盖的最小次数。但是较难的地方是:如何判断某一条边是被那个区间覆盖的。其实我们可以再维护一个值,把覆盖这个点的区间的编号加起来,因为我们找线段时只是找被覆盖一次的线段,所以一定就是他的编号了。因此在删区间的时候,额外维护这个变量。
另一个比较难的地方:找到你要删的那条边后,把它赋成inf,他就不会对答案产生影响了(维护的是区间最小值,0可是比1小的。。),我曾经卡在一个地方,就是在删区间时删出来一个0怎么办。那么这个0一定不会再被那一个区间选择了。但是很明显每条边都是要被选的,那这就一定无解了。
注:把边权下放到点时注意把用不到的点赋成无限大。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 #define N 200005 7 #define inf 1000000000 8 #define mem(x) (memset(x,0,sizeof(x))) 9 #define ll long long 10 using namespace std; 11 struct road{int v,next;}lu[N*2]; 12 struct node{int x,y;}a[N]; 13 int T,ans,n,e,cnt,adj[N],f[N],top[N],sz[N],son[N],id[N],dep[N]; 14 void add(int u,int v){lu[++e]=(road){v,adj[u]};adj[u]=e;} 15 namespace TREE 16 { 17 struct tree{int l,r,su,lsu;ll h,lh;}t[N*4]; 18 inline void build(int l,int r,int x) 19 { 20 t[x].l=l;t[x].r=r; 21 t[x].h=t[x].lh=t[x].lsu=t[x].su=0; 22 if(l==r)return; 23 int mid=l+r>>1; 24 build(l,mid,x*2); 25 build(mid+1,r,x*2+1); 26 } 27 inline void down(int x) 28 { 29 int h=t[x].lh,su=t[x].lsu; 30 t[x].lh=t[x].lsu=0; 31 t[x*2].h+=h;t[x*2].lh+=h; 32 t[x*2+1].h+=h;t[x*2+1].lh+=h; 33 t[x*2].su+=su;t[x*2].lsu+=su; 34 t[x*2+1].su+=su;t[x*2+1].lsu+=su; 35 } 36 inline void Q(int x) 37 { 38 if(t[x].l==t[x].r){ans=t[x].h,t[x].su=inf;return;} 39 if(t[x].lh)down(x); 40 if(t[x*2].su==1)Q(x*2); 41 else Q(x*2+1); 42 t[x].su=min(t[x*2].su,t[x*2+1].su); 43 } 44 inline void add(int l,int r,int k,ll h,int x) 45 { 46 if(t[x].l>=l&&t[x].r<=r) 47 { 48 t[x].su+=k;t[x].lsu+=k; 49 t[x].h+=h;t[x].lh+=h; 50 if(l==1)t[x].su=inf; 51 return; 52 } 53 if(t[x].lh)down(x); 54 int mid=t[x].l+t[x].r>>1; 55 if(l<=mid)add(l,r,k,h,x*2); 56 if(r>mid)add(l,r,k,h,x*2+1); 57 t[x].su=min(t[x*2].su,t[x*2+1].su); 58 } 59 inline void C(int x,int y,int k,ll h) 60 { 61 int fx=top[x],fy=top[y]; 62 while(fx^fy) 63 { 64 if(dep[fx]<dep[fy])swap(fx,fy),swap(x,y); 65 add(id[fx],id[x],k,h,1); 66 x=f[fx],fx=top[x]; 67 } 68 if(x==y)return; 69 if(id[x]>id[y])swap(x,y); 70 add(id[x]+1,id[y],k,h,1); 71 } 72 } 73 using namespace TREE; 74 inline void dfs1(int x,int fa) 75 { 76 f[x]=fa;sz[x]=1;dep[x]=dep[fa]+1; 77 for(int i=adj[x];i;i=lu[i].next) 78 { 79 int to=lu[i].v;if(to==fa)continue; 80 dfs1(to,x);sz[x]+=sz[to]; 81 if(sz[to]>sz[son[x]])son[x]=to; 82 } 83 } 84 inline void dfs2(int x,int y) 85 { 86 top[x]=y;id[x]=++cnt; 87 if(!son[x])return; 88 dfs2(son[x],y); 89 for(int i=adj[x];i;i=lu[i].next) 90 { 91 int to=lu[i].v; 92 if(to==f[x]||to==son[x])continue; 93 dfs2(to,to); 94 } 95 } 96 bool check() 97 { 98 dfs1(1,0);dfs2(1,1);build(1,n,1);add(1,1,1,inf,1); 99 for(int i=1;i<n;i++)C(a[i].x,a[i].y,1,i); 100 for(int i=1;i<n;i++) 101 { 102 if(t[1].su!=1)return 0; 103 ans=0;Q(1); 104 C(a[ans].x,a[ans].y,-1,-ans); 105 } 106 return 1; 107 } 108 int main() 109 { 110 scanf("%d",&T); 111 while(T--) 112 { 113 scanf("%d",&n);e=cnt=0; 114 mem(sz);mem(son);mem(f);mem(top);mem(adj);mem(dep);mem(id); 115 for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x); 116 for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),a[i]=(node){x,y}; 117 if(check())printf("YES\n"); 118 else printf("NO\n"); 119 } 120 }