虚树

虚树

  1. 适用范围
    1. 虚树常常用来处理询问的点数远小于处理询问要经过的树上的点数的一类问题。
  2. 简单做法
    1. 把所有点和他们任意两个的LCA求出来,将它们按照父子关系构建一棵树,
    2. 还要想好两两之间的边权如何处理
  3. 构建方法
    1. 首先把所有询问的点按照在原树的 d f s dfs dfs序排序,我们还需要一个栈来维护从根到当前节点的链。
    2. 1 1 1号点加进去,为了保证3不会把栈弹空
    3. 每枚举到一个点,如果栈为空,直接入栈,否则求它和栈顶的 l c a lca lca。 对于这个 l c a lca lca和栈顶元素的 d f s dfs dfs序有下面三种关系:
      1. d f n [ l c a ] = = d f n [ s [ t o p ] ] dfn[lca]==dfn[s[top]] dfn[lca]==dfn[s[top]],说明栈顶就是 l c a lca lca,直接把当前元素入栈。
      2. d f n [ l c a ] < d f n [ s [ t o p ] ] 但 是 d f n [ l c a ] > = d f n [ s [ t o p − 1 ] ] dfn[lca]<dfn[s[top]] 但是 dfn[lca]>=dfn[s[top-1]] dfn[lca]<dfn[s[top]]dfn[lca]>=dfn[s[top1]],由于我们维护的是一个链,就可以让栈顶出栈, l c a lca lca入栈
      3. 否则,一直 p o p pop pop到出现上面的情况
    4. 加完 l c a lca lca加最后再加枚举到的点。
    5. 至于连边,显然一个点出去的时候,它只会和上面的那个点连边,所以弹出的时候要连下边,最后如果栈不为空也要连边。
    6. 在实践中其实不需要判断 d f s dfs dfs序,只需要判断深度就可以辣。
  4. 参考代码
    1. sort(a+1,a+1+m,cmp); 
      if(!bel[1]) st[++top]=1;
      int temp;
      for(int i=1;i<=m;i++)
      {
      	if(!top)
      	{
      		st[++top]=a[i];
      		continue;
      	}
      	temp=lca(a[i],st[top]);
      	while(1)
      	{
      		if(dep[st[top-1]]<=dep[temp])
      		{
                  if(temp!=st[top])
      				add(temp,st[top]); 
      			top--;
      			if(st[top]!=temp) st[++top]=temp;
      			break;
      		}
      		add(st[top-1],st[top]);
      		top--;
      	}
      	if(st[top]!=a[i]) st[++top]=a[i];
      }
      while(top>1) add(st[top-1],st[top]),top--;
      
  5. 经典例题
    1. 2020牛客暑期多校训练营(第一场)
      1. 这个题有一个虚树上的重要结论:每次求 l c a lca lca本质上是求和上一个要添加的元素的 l c a lca lca,即不会出现求 l c a lca lca l c a lca lca l c a lca lca
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值