C语言dfs加lca共同祖先,遍历邻接表来计算节点不同类型个数,逐行注释,对应蓝桥杯买零食题目

#define N 1000

#define max 23

//邻接表节点结构

typedef struct node{

      int to;   //节点

      struct node* next;//指向下一个节点

}node;

//邻接表表头结构

typedef struct{

          node * head;

}list;

//需要用到的数据类型

int type[N];   //节点类型

int a[N][max];  //节点类型的个数

int fa[N][max];//父结点信息

int dep[N];//当前树深

//初始化

void init(list* l){  

    l->head==NULL;

}

//添加邻接表的节点

void add(list* l,int u,int v){

        node* newnode;

        newnode=(node*)malloc(sizeof(node));

        node->to=v;

        node->next=l->head;

}

//深度搜索,构建树

void dfs(int u,int f){

        fa[v][0]=f;//比如bfs(1,0),1的父节点就是0;

        dep[v]=dep[f]+1;

        for(int i=0;i<=MAX;i++){

                a[v][i]=a[f][i];//记录父节点

                a[v][type[v]]++;//记录节点类型

        }

        for(int k=1;(1<<k)<=dep[v]-1;k++){

                fa[v][k]=fa[fa[v][k-1]][k-1]//通过深度计算节点的父节点

        }

        node *p=t1[v].head;

        while(p!=NULL){

                int u=p->to;

                if(u!=f)dfs(u,v);

                p=p->next;

        }

}

//计算公共祖先,lca

int lca(int u,int v){

        if(dep[u]<dep[v]){

                int temp=u;

                u=v;

                v=temp;

        }//找出深度深的,后续好进行同层处理

        for(int k=20;k>=0;k--){

                if(dep[v]+(1<<k)<=dep[u]){

                         u=fa[u][k];       

                }

        }//v是深层的,(1<<K)表示的是2的k次方,通过这个方式找到v的父节点层数和u一样

        if(u==v)return u;

        for(int k=20;k>=0;k--){

                if(fa[u][k]!=fa[v][k]){

                        u=fa[u][k];

                        v=fa[v][k];

                }

        }//找出公共祖先

        return fa[v][0];

}

//主函数

int main(){
    int n,q;
    scanf("%d %d",&n,&q);
    int k,i,j,tmp=0;
    for(i=1;i<=n;i++){
        scanf("%d",&tmp);
        type[i]=tmp;
    }
    for(k=0;k<n-1;k++){
        scanf("%d %d",&i,&j);
        add(&t1[i],i,j);
        add(&t1[j],j,i);
    }
    dep[0]=0;
    dfs(1,0);
    int begin,end;
    while (q--) {
        scanf("%d %d", &begin, &end);
        int fa=lca(begin,end);
        int ans=0;
        for(i=1;i<=22;i++){
            int val=a[begin][i]+a[end][i]-2*a[fa][i]+(i==type[fa]);
            if(val>0)ans++;
        }
        printf("%d\n",ans);
    }
     for (i = 1; i <= n; i++) {
        node* p = t1[i].head;
        while (p != NULL) {
            node* temp = p;
            p = p->next;
            free(temp);
        }
    }
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值