虚树模板(用到lca)

虚树这一个知识点刚开始看都摸不清头脑,集中精力看了一个多小时发现原来挺简单的,可能是理解了的东西都会觉得简单吧。。这边有位大佬写的可以–》》https://www.cnblogs.com/chenhuan001/p/5639482.html不过它的这个lca我觉得没我的清晰。。可能是我太菜了,看不懂他优化了的吧。。

下面是我写的模板:

#include <bits/stdc++.h>
using namespace std;

const int N = 10010;

struct edge{    //链式向前星
    int to,next;
}edges[N<<1];

int head[N],cnt;    

void add_edge(int u,int v){ //连边
    edges[++cnt].next = head[u];
    edges[cnt].to = v;
    head[u] = cnt;
}

//fa:表示每个节点的祖先,dep:表示每个节点的深度,id:表示每个节点的编号
int fa[N][50],dep[N],lg[N],id[N],ind;
int n,m,s;  //n:表示节点数以及n-1条边,m:表示查询的节点有m个,s表示根

/**
 *  lg_init():初始化log2 
*/
void lg_init(int n){

    for(int i = 1;i<=n;i++){
        lg[i] = lg[i-1] + (1 << lg[i-1] == i);
    }
}

/**
 *  dfs():找出每个节点的2^(i-1)的祖先,每个节点的深度,给每个节点编号
*/
void dfs(int x,int fath){
    fa[x][0] = fath, dep[x] = dep[fath] + 1,id[x] = ++ind;

    for(int i = 1;i<=lg[dep[x]]; i++){

        fa[x][i] = fa[fa[x][i-1]][i-1];
    }
    
    for(int i = head[x]; i; i = edges[i].next){

        int to = edges[i].to;
        
        if(to != fath) dfs(to,x);
    }
}

/**
 *  LCA():求最近公共祖先
*/
int LCA(int x,int y){

    if(dep[x] < dep[y]) swap(x,y);

    while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];

    if(x == y) return x;

    for(int i = lg[dep[x]] - 1; i >= 0; i--){

        if(fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i];
    }

    return fa[x][0];
}

// 虚树邻接表
vector<int> vtree[N];    
vector<int> vtreew[N];
int stk[N],top; //存放虚树节点的栈
int mark[N];    //标记
/**
 *  tree_add():给虚树节点连边
 */
void tree_add(int u,int v,int w){
    vtree[u].push_back(v);
    vtree[v].push_back(u);
    vtreew[u].push_back(w);
    vtreew[v].push_back(u);
}

struct Vtree{
    int id,order;
}tree[N];

int cmp(Vtree a,Vtree b){
    return a.order < a.order;
}

int build_vtree(int vp[],int vn){

    if(vn == 0) return -1;
    
    top = 0;
    stk[top++] = vp[0];
    vtree[vp[0]].clear();
    vtreew[vp[0]].clear();
    mark[vp[0]] = 1;

    for(int i = 1;i<vn;i++){

        int v = vp[i];

        int lca = LCA(stk[top-1],v);

        if(lca == stk[top-1]);  //如果v和栈顶结点的公共祖先 == 栈顶元素,那么不用做任何操作
        else{

            int pos = top-1;

            while(pos>=0 && dep[stk[pos]] > dep[lca]) pos--;
            pos++;

            for(int j = pos; j<top-1;j++){
                tree_add(stk[j],stk[j+1],dep[stk[j+1]] - dep[stk[j]]);
            }

            int prepos = stk[pos];

            if(pos == 0){
                vtree[lca].clear(),vtreew[lca].clear(),stk[pos] = lca, top = pos+1;
                mark[lca] = 0;
            }
            else if(stk[pos] != lca){
                vtree[lca].clear(),vtreew[lca].clear(),stk[pos] = lca,top = pos+1;
                mark[lca] = 0;
            }else
                top = pos;
            tree_add(prepos,lca,dep[prepos] - dep[lca]);
        }
        vtree[v].clear();
        vtreew[v].clear();
        stk[top++] = v;
        mark[v] = 1;
    }
    for(int i = 0;i<top-1;i++){
        tree_add(stk[i],stk[i+1],dep[stk[i+1]] - dep[stk[i]]);
    }
    return vp[0];
}

int solve(int vp[],int vn){

    for(int i = 0;i<vn;i++) tree[i].id = vp[i],tree[i].order = id[vp[i]];

    sort(tree,tree+vn,cmp);

    for(int i = 0;i<vn;i++) vp[i] = tree[i].id;

    return build_vtree(vp,vn);
}

void print(int x,int fath){

    printf("%d ",x);

    for(int i = 0;i<vtree[x].size();i++){
        
        if(vtree[x][i] != fath) print(vtree[x][i],x);
    }
}

int main(){

    cin >> n >> m >> s;

    int u,v;
    for(int i = 0;i<n-1;i++){
        cin >> u >> v;
        add_edge(u,v);
        add_edge(v,u);
    }
    lg_init(n);
    dfs(s,0);
    int save[m];
    for(int i = 0;i<m;i++) cin >> save[i];
    int root = solve(save,m);
    if(root != -1){
        print(root,fa[root][0]);
    }
    // cout << LCA(4,5) << endl;
    system("pause");
    return 0;
}

/*
7 3 1
1 3
1 2
2 6
3 5
3 4
4 7
6 7 5
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值