树的相关知识

树的邻接表存储

const int N=1e5+10;
int tot; //边的编号,从0开始,奇数为正向边,偶数为反向边
int ver[2*N]; //下标为边的编号,存储的是 某条边 到达 哪个点
int edge[2*N];//下标为边的编号,存储的是 某条边 的权值
int Next[2*N];//下标为边的编号,存储的是 某条边 (作为某个点的出边集合中)的下一条边的编号
int head[N];  //下标为节点的编号,存储的是 某个节点(的出边集合中)的第一条边的编号
int pre[N];   //下标为节点的编号,存储的是 某条节点 是通过哪条边到达的

void add(int x, int y, int z) {
    ver[++tot] = y; //存到达点
    edge[tot] = z;  //存边的权值
    Next[tot] = head[x]; //新读入的边 设置 起点的第一条出边编号 作为自己的下一条边
    head[x] = tot; //新读入的边插队
}

int main() {
    cin >> n;
    for(int i = 1; i < n; i++) {
        int x,y;
        cin >> x >> y;
        add(x, y, 1);
        add(y, x, 1);
    }

    return 0;
}

树的DFS

void dfs(int x) {
	vis[x] = 1;
	for(int i = head[x]; i; i = Next[i]) {
		int y = ver[i];
		if(vis[y]) continue;	//因为无向图边会正反存两次 
		dfs(y);
	}
}

树的时间戳

void dfs(int x) { 
	dfn[x] = ++cnt;
	for(int i = head[x]; i ; i = Next[i]) {
		int y = ver[i];
		if(dfn[y]) continue;
		dfs(y);
	}
}

树的DFS序

void dfs(int x) {
	a[++m] = x; //存储dfs序,进入
	vis[x] = 1;
	for(int i = head[x]; i; i = Next[i]) {
		int y = ver[i];
		if(vis[y]) continue;
		dfs(y);
	}
	a[++m] = x; //存储dfs序,离开
}

树的深度

void dfs(int x) {
	vis[x] = 1;
	for(int i = head[x]; i; i = Next[i]) {
		int y = ver[i];
		if(vis[y]) continue;
		d[y] = d[x] + 1; //计算深度
		dfs(y);
	}
}

树的重心

void dfs(int x) {
	vis[x] = 1;
	size[x] = 1; //子树的大小,默认为自身一个节点
	int max_part = 0; 
	for(int i = head[x]; i; i = Next[i]) {
		int y = ver[i];
		if(vis[y]) continue;
		dfs(y);
		size[x] += size[y]; //从子节点向父节点递推
		max_part = max(max_part, size[y]);
	}
	max_part = max(max_part, n - size[x]); //n为整棵树的节点数量
	if(max_part < ans) {
		ans = max_part; //全局变量 ans 记录重心对应的 max_part
		pos = x; //全局变量 pos 记录重心
	}
}

树的直径

BFS求树的直径



int bfs(int t) {
    memset(v,0,sizeof(v));
    memset(dis,0,sizeof(dis));
    queue<int>q;
    q.push(t);
    v[t] = 1;
    int maxx = 0;
    int index = t;
    while(q.size()) {
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = Next[i]) {
            int y = ver[i];
            if(!v[y]) {
                dis[y] = dis[x] + edge[i];
                if(dis[y] > maxx){
                    maxx = dis[y];
                    index = y;
                }
                v[y] = 1; q.push(y);
            }
 
        }
    }
    return index;
}

// int main(){}
    int T1=bfs(1);
    int T2 = bfs(T1);

树形DP求树的直径

int ans = 0;
void dp(int x) {
    v[x] = 1;
    for(int i = head[x]; i; i = Next[i]) {
        int y = ver[i];
        if(v[y]) continue;
        dp(y);
        ans = max(ans, d[x] + d[y] + edge[i]);
        d[x] = max(d[x], d[y] + edge[i]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值