树基础4.28

,1、常见的输入树的情况

(1)输入每个结点的父亲编号

//输入每个点的父亲
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define N 10010
vector<int>vec[N];
int x,n,vis[N];
void dfs(int x){
    vis[x]=1;
    for(int i=0;i<vec[x].size();i++){
        if(!vis[vec[x][i]])dfs(vec[x][i]);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        scanf("%d",&x);
        vec[x].push_back(i);//记录每个点的儿子,x点的儿子是第i个点
    }
    dfs(1);
    return 0;
}

(2)输入n-1条边的信息 不定根

//给出n-1条边的信息 遍历树
#include<iostream>
#include<vector>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
#define N 10010
vector<int>vec[N];
int dad[N],x,y,n;
void dfs(int x)
{
    for(int i=0;i<vec[x].size();i++){//遍历和它相连的边
        if(dad[x]!=vec[x][i]){
            dad[vec[x][i]]=x;
            dfs(vec[x][i]);//进行深搜;
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);//储存双向边
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    dfs(1);
    return 0;
}

2、求树的直径
树上最长的简单路径为树的直径

在树上任选一点u,以u为根进行一遍dfs,求距离u最远的点s,以s为根进行一遍dfs,找到距离s最远的点t,点s和点t之间的路径为树的直径;

//求树的直径
#include<iostream>
#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
#define N 10010
vector<int>vec[N];
int x,y,n,t,s,dis[N];
void dfs(int x)
{
    for(int i=0;i<vec[x].size();i++){
        if(!dis[vec[x][i]]){//没有访问过
            dis[vec[x][i]]=dis[x]+1;//dis[vec[x][i]]到x的距离为dis[x]的距离+1
            dfs(vec[x][i]);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    dfs(1);//随便找一个点
    for(int i=1;i<=n;i++){
        if(dis[i]>dis[t])t=i;//找出和它距离最大的那个点
    }
    memset(dis,0,sizeof(dis));//一定要清0
    dfs(t);//再找距离t最大的点
    for(int i=1;i<=n;i++){
        if(dis[i]>dis[s])
        s=i;
    }
    printf("%d",dis[s]);//这个点到t点的距离为树的直径
    return 0;
}

3、找到一个点,其所有的子树中最大的子树结点数最少,这个点就是这个树的重心;树的总点数为偶数时,可能会有两个重心。

先随意确定一个根,之后通过一遍dfs将所有子树的大小求出来。

如果有一个点i满足2*size i >=n,并且它的儿子都满足2*size son i <=n,那么这个点就是这个树的重心;

//求树的重心
#include<iostream>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
#define N 10010
vector<int>vec[N];
int ans,x,y,n,sizd[N],dad[N];
void dfs(int x)
{
    size[x]=1;
    for(int i=0;i<vec[x].size();i++)
    {
        if(dad[x]!=vec[x][i])
        {
            dad[vec[x][i]]=x;
            dfs(vec[x][i]);
            size[x]+=size[vec[x][i]];//它本身的个数加上它儿子结点的个数
        }
    }
    if(size[x]*2>=n&&!ans)//满足重心的条件
    {
        ans=x;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        vec[x].push_back(y);//建边
        vec[y].push_back(x);
    }
    dfs(1);//搜每个点子树结点的个数
    printf("%d",ans);
    return 0;
} 
时间: 2024-08-25 18:56:54

树基础4.28的相关文章

线段树 基础单点更新 敌兵布阵

题:敌兵布阵 标准线段树模板代码: #include<cstdio> #include<cstring> const int maxn = 500000 + 10; struct Node{ int left, right, count; }node[maxn]; int a[maxn]; /*********************************** ***************建树**************** ************i是区间序号********

线段树基础知识----(基础数据结构)--(一)

1.定义 引入:为什么要使用线段树而不用数组模拟呢? answer:因为有些题用数组来做就要超时,用线段树的O(log(n))的时间复杂度刚好可以求解 毫无疑问线段树是一种数据结构,但是它实际是一个类似树状的链表结构(个人认为) ///还是要正经一点(照搬教科书)----------- / ////////////////////////////////////////////////////////////////////// 线段树定义:线段树是一种二叉搜索树,与区间树相似,它将一个区间划分

线段树基础

关于线段树的原理学习,可以参看杨弋大牛的论文<线段树>以及刘汝佳老师的<算法竞赛入门经典(训练指南)>,代码风格学习hzwer或者notonlysuccess均可. 一.单点更新 最基础的线段树 题目:codevs1080 链接:http://codevs.cn/problem/1080/ 分析:最简单的线段树,单点更新,区间求和 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4

HDU 1754--I Hate It(线段树基础)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 44820    Accepted Submission(s): 17591 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

伸展树基础(Splay)

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3948  Solved: 1627 [Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为

hihoCoder 1014 Trie树(基础字典树)

题意  中文 最基础的字典树应用噢噢噢噢 #include<cstdio> #include<cstring> using namespace std; struct trie { trie *chi[26]; int num; trie() { num = 0; for(int i = 0; i < 26; ++i) chi[i] = NULL; } }*root; void insertTrie(char s[]) { trie *p = root; p->num+

【线段树基础】NKOJ 1321 数列操作

时间限制 : 10000 MS   空间限制 : 165536 KB 问题描述 假设有一列数{Ai}(1≤i≤n),支持如下两种操作:将Ak的值加D.(k, D是输入的数)输出As+As+1+…+At.(s, t都是输入的数,S≤T) 输入格式 第一行一个整数n,第二行为n个整数,表示{Ai}的初始值≤10000.第三行为一个整数m,表示操作数下接m行,每行描述一个操作,有如下两种情况:ADD k d (表示将Ak加d,1<=k<=n,d为数,d的绝对值不超过10000)SUM s t (表示

POJ2528线段树基础

开始就直接用延迟标记搞了下,最后发现内存肯定会爆了,数据太大了: 问了瓜神,原来应该用离散化来做这题,具体见注释 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #in

划分树基础知识

原网址:划分树详解 对4 5 2 8 7 6 1 3 分别建划分树和归并树 划分树如下图 红色的点是此节点中被划分到左子树的点. 我们一般用一个结构体数组来保存每个节点,和线段树不同的是,线段树每个节点值保存一段的起始位置和结束位置,而在划分树和递归树中,每个节点的每个元素都是要保存的.为了直观些,我们可以定义一个结构体数组,一个结构体中保存的是一层的元素和到某个节点进入左子树的元素的个数,不同于线段树,我们不能保存一个节点的起始结尾位置,因为随层数的增加,虽然每个结构体保存的元素数目是一定的,