虚树学习笔记

· · 个人记录

在一些树上问题中,可能会有一些询问,每次询问给出一些关键点,这些关键点的总数是可以接受的,但是我们不能对于每一次询问都进行一次对所有点的遍历,可以发现的是由于总数一定,所以关键点相对于所有点来说都是很稀疏的。我们可不可以重构这颗树,让树上面只剩下关键点呢?虚树就是为了解决这样一类问题而诞生的。

void build(){
    sort(h+1,h+m+1,cmp);//按照dfs序排序 
    top=0;idx=0;//清空链式前向星 
    stk[++top]=1;//不管 1 是不是关键点,优先加入 1
    for(int i=1;i<=m;i++){
        if(h[i]==1) continue;
        int lca=LCA(stk[top],h[i]);
        if(lca!=stk[top]){
            while(dfn[stk[top-1]]>dfn[lca])  add(stk[top-1],stk[top]),top--;//add 指加边操作 
            if(stk[top-1]!=lca){
                head[lca]=0;//清空前向星 
                add(lca,stk[top]);//lca 处于两者之间,那么下一个点应该是 lca 的儿子 
                stk[top]=lca;
            }
            else{
                add(stk[top-1],stk[top]);//直接加 
                top--;
            }
        }
        head[h[i]]=0;
        stk[++top]=h[i];
    } 
    for(int i=1;i<top;i++) add(stk[top],stk[top+1]);//加上没加的边 
}