zoukankan      html  css  js  c++  java
  • 虚树学习

    口胡一下怕忘了。应该会有错留坑回来改。

    例题:bzoj2286: [Sdoi2011]消耗战 

    哔哔一下题意:边有边权。$m$次询问,每次给定$k$个点,割掉若干条边使得$1$号点与给定的点不连通,要求代价最小。

    $n leq 2e5 , sum k leq 5e5$

    首先这个$sum k$就很特别。是建虚树的契机。

    我们不可能每次跑一遍$O(n)$的树$dp$,那我们能不能每次$O(k)$呢?

    做法就是每回只在关键点上做$dp$,就要求我们建出只有关键点的树。即虚树。注意关键点不仅是给定的$k$个点,还有它们所有点两两的LCA。

    实际上算上LCA也只有不超过$2k$个点。想一想为什么。(没事,我自己想想而已)

    靠全是废话。直接说咋构建。

    所有点按dfs序排序。按顺序插入栈中。设栈顶元素为$p$,现在要插入$x$。

    栈里维护的是根到$p$的一条链。每插入一个点,和栈顶只有两种关系:

    $p$和$x$的LCA是$p$;是另一个点(可能在栈里可能不在,可能是给定点可能不是)。根据dfs序,不存在第三种情况。

    第一种情况,直接进栈,注意不用加边。因为可能会出现和之后点的LCA在$p$之下,这种情况下应该是$p$连这个LCA,LCA再连$x$。而这时候这个LCA还不知道是谁甚至有没有。

    另一种情况,我们令$LCA(p,x)$为$fa$。这时说明$p$的子树已经遍历完了,不然不会轮到$x$。我们前面说过这个$fa$可在可不在,但一定在栈当前维护的链上。(真tm废话)于是开始弹栈。

    我们称栈顶的第二个元素为$q$,如果$q$的深度(这里用dfs序也是一样的道理)大于$fa$,$fa$在$q$之上,$p$与$q$连边,弹出$q$。直到$q$的深度等于或者小于$fa$的,说明$q$就是$fa$或者$fa$在$p,q$之间,$fa,p$连边,$fa$入栈,$p$弹栈(要是$fa=q$就不用了),$x$入栈。

    所有点对的LCA我们可以$O(logn)$时间求出,所以所有询问构建虚树的总复杂度就是$O(sum k logn)$的。听着高大上的东西,其实道理很简单。给我的感觉就是和缩点的$tarjan$算法一样,只是一个工具,难点还是在于$dp$吧。

    板子等我熟练了在贴吧。。


    upd

    可能就是这样吧 

    s[++top]=1;
    for(int i=(a[1]==1)+1;i<=k;i++){
        int f=lca(a[i],s[top]);
        if(f==s[top]){
            s[++top]=a[i];continue;
        }
        while(1){
            if(dep[s[top-1]]<=dep[f]){
                add(f,s[top]);
                top--;
                if(s[top]^f)s[++top]=f;
                break;
            }
            add(s[top],s[top-1]);
            top--;
        }
        s[++top]=a[i];
    }
    while(--top)add(s[top],s[top+1]);
  • 相关阅读:
    此时的我,就像一个炸药包...
    我焦躁,并不只是心里承受,还是因为我上面担着。
    我们应该顶住压力
    git初识后的一些问题
    我近期应该找个机会休整一下了
    权限管理设计的一些感悟
    一个无用的功能
    关于IE8与FireFox中,button内字体总是有一个不垂直居中的问题
    Android之EditText文本框监听事件
    Android流量统计TrafficStats类的使用
  • 原文地址:https://www.cnblogs.com/orzzz/p/8232344.html
Copyright © 2011-2022 走看看