利用DFS序求树中以某点为根节点的子树

定义 :在一棵树中,每一个节点在dfs深度优先遍历的时间序列(将树形结构转化为线性结构)

在这里插入图片描述
在这里插入图片描述

核心代码及数据结构

vector<int> tree[100];   //存放的栈,为什么不用数组?因为栈好处理
int in[100];    //进入的时间戳
int out[100];    //出去的时间戳
int num[200];    //存放树dfs序列||树的前序遍历
int t = 0;        //记录序列的时间

void dfs(int x, int fa) {
    in[x] = ++t; //进入的时间戳
    num[t] = x;  //生成新的线性结构
    for(int i = 0; i < tree[x].size(); i++) {
        int cnt = tree[x][i];
        if(cnt == fa) continue;
        dfs(cnt, x);
    }
    out[x] = t;  //出去的时间戳
}

题目:求树中以某点为根节点的子树

代码

#include <bits/stdc++.h>
using namespace std;
vector<int> tree[100];   //存放的栈,为什么不用数组?因为栈好处理
int in[100];    //进入的时间戳
int out[100];    //出去的时间戳
int num[200];    //存放树dfs序列||树的前序遍历
int t = 0;        //记录序列的时间


void dfs(int x, int fa) {
    in[x] = ++t; //进入的时间戳
    num[t] = x;  //生成新的线性结构
    for(int i = 0; i < tree[x].size(); i++) {
        int cnt = tree[x][i];
        if(cnt == fa) continue;
        dfs(cnt, x);
    }
    out[x] = t;  //出去的时间戳
}
int main()
{
    int n;  //n表示多少结点
    int u, v;
    int r,op; //r表示以某点作为子树的根节点,op表示询问多少次数
    while(scanf("%d %d", &n,&op) != EOF)
    {
        for(int i = 0; i < n-1; i++)
        {
            scanf("%d %d", &u, &v);
            tree[u].push_back(v);
            tree[v].push_back(u);
        }
        dfs(1, -1);
        
        //显示数组
        /*
        for(int i=1;in[i]!=0;i++)
        {
            cout<<in[i];
        }
        cout<<endl;
        for(int i=1;out[i]!=0;i++)
        {
            cout<<out[i];
        }
        cout<<endl;
        for(int i=1;num[i]!=0;i++)
        {
            cout<<num[i];
        }
        cout<<endl;
        */
        while(op--)
        {
            cin>>r;
            for(int i=in[r];i<=out[r];i++)
            {
                cout<<num[i];
            }
            cout<<endl;
        }
    }
    return 0;
}

运行结果

在这里插入图片描述

题目:

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 r 的点权增加 s 。
操作 2 :把某个节点 r 为根的子树中所有点的点权都增加 s 。
操作 3 :查询以第r节点为根节点的子树
操作4:查询以第r节点为根节点的子树节点和

代码

#include <bits/stdc++.h>

using namespace std;


vector<int> tree[100];   //存放的栈,为什么不用数组?因为栈好处理
int in[100];    //进入的时间戳
int out[100];    //出去的时间戳
int num[200];    //存放树dfs序列||树的前序遍历
int t = 0;        //记录序列的时间

void dfs(int x, int fa) {
    in[x] = ++t; //进入的时间戳
    num[t] = x;  //生成新的线性结构
    for(int i = 0; i < tree[x].size(); i++) {
        int cnt = tree[x][i];
        if(cnt == fa) continue;
        dfs(cnt, x);
    }
    out[x] = t;  //出去的时间戳
}
int main()
{
    int n,m;  //n表示多少结点
    int u, v;
    int r,op,s; //r表示以某点作为子树的根节点,op表示询问多少次数
    while(scanf("%d %d", &n,&m) != EOF)
    {
        for(int i = 0; i < n-1; i++)
        {
            scanf("%d %d", &u, &v);
            tree[u].push_back(v);
            tree[v].push_back(u);
        }
        dfs(1, -1);

        //显示数组
        /*
        cout<<"第i节点子树的入栈时间:";
        for(int i=1;in[i]!=0;i++)
        {
            cout<<in[i];
        }
        cout<<endl;
        cout<<"第i节点子树的出栈时间:";
        for(int i=1;out[i]!=0;i++)
        {
            cout<<out[i];
        }
        cout<<endl;
        cout<<"DFS序列(前序遍历)  :";
        for(int i=1;num[i]!=0;i++)
        {
            cout<<num[i];
        }
        cout<<endl;

        */
       while(m--)
        {
            cin>>op;
            if(op==1) //op==1时,以第r节点加s
            {
                cin>>r>>s;
                num[r] = num[r]+s;
            }
            if(op==2)  //op==2时,以第r节点为根节点的子树节点加s
            {
                cin>>r>>s;
                for(int i=in[r];i<=out[r];i++)
                {
                    num[i]= num[i]+s;
                }
            }
            if(op==3) //op==3时,查询以第r节点为根节点的子树
            {
                cin>>r;
                for(int i=in[r];i<=out[r];i++)
                {
                    cout<<num[i];
                }
                cout<<endl;
            }
            if(op==4) //op==4时,查询以第r节点为根节点的子树的节点和
            {
                cin>>r;
                int sum=0;
                for(int i=in[r];i<=out[r];i++)
                {
                    sum= sum+num[i];
                }
                cout<<sum<<endl;
            }
        }
    }
    return 0;
}

运行结果

在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值