树链剖分 树

很明显一点,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 }
View Code

 

posted @ 2017-10-24 20:55  Hzoi_QTY  阅读(117)  评论(0编辑  收藏  举报