zoukankan      html  css  js  c++  java
  • 树链剖分 树

    很明显一点,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
    ");
    118         else printf("NO
    ");
    119     }
    120 }
    View Code
  • 相关阅读:
    Leetcode 15 3Sum
    Leetcode 383 Ransom Note
    用i个点组成高度为不超过j的二叉树的数量。
    配对问题 小于10 1.3.5
    字符矩阵的旋转 镜面对称 1.2.2
    字符串统计 连续的某个字符的数量 1.1.4
    USACO twofive 没理解
    1002 All Roads Lead to Rome
    USACO 5.5.1 求矩形并的周长
    USACO 5.5.2 字符串的最小表示法
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7725675.html
Copyright © 2011-2022 走看看