树章节习题

2024-08-25 13:44
文章标签 习题 章节

本文主要是介绍树章节习题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天也是小小的把树的章节的内容大体过了一遍,总共有树上dp,LCA(最近公共祖先),树的直径,以及树上差分

P1395 会议

很经典的树上dp里面的换根dp问题,现在这里说几个数组

sz数组,用于统计以1为节点,每个节点的子树大小

sum数组,用于统计每个子树上总节点的累加

f 数组,用于统计以每个点为根的时候的路径长度

我们通过画图分析可知,换根公式为 f [ v ] = f [ u ] - sz [ u ] + ( n - sz [ u ])

我们就可以完成这个题目了

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
int u,v;
vector<int> e[50005];
int sz[50005];
int sum[50005];
int f[50005];void dfs1(int v,int fa)
{sz[v]=1;for(int u:e[v]){if(u!=fa){dfs1(u,v);sz[v]+=sz[u];}}
}void get(int v,int fa)
{sum[v]=0;for(int u:e[v]){if(u!=fa){get(u,v);sum[v]+=sz[u]+sum[u];}}
}void dfs2(int v,int fa)
{for(int u:e[v]){if(u!=fa){f[u]=f[v]-sz[u]+(n-sz[u]);dfs2(u,v);}}
}
signed main()
{cin>>n;for(int i=1;i<n;i++){cin>>u>>v;e[u].push_back(v);e[v].push_back(u);}dfs1(1,0);get(1,0);f[1]=sum[1];dfs2(1,0);int maxn=0x3f3f3f3f,flag=0;for(int i=1;i<=n;i++){if(f[i]<maxn){flag=i;maxn=f[i];}}cout<<flag<<" "<<maxn;return 0;
} 

P3128 [USACO15DEC] Max Flow P

这道题乍一看,我没看出来哪里有最近公共祖先的思想,但是,后面在纸上写写画画的时候,发现 这其实就是最近公共祖先+树上差分

我们每次要在树上对每次提问的路径进行修改,那么我们这个是点修改,因此我们需要将经过的两个点的差分数组dif++,最近公共祖先和其父节点dif--

然后就直接出来了

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int u,v;
vector<int> e[50005];
int dep[50005];
int f[50005][17];
int dif[50005];
int ans;
void dfs(int v,int fa)
{dep[v]=dep[fa]+1;f[v][0]=fa;for(int i=1;i<17;i++){f[v][i]=f[f[v][i-1]][i-1];}for(int u:e[v]){if(u!=fa){dfs(u,v);}}
}
int lca(int u,int v)
{if(dep[u]<dep[v]){swap(u,v);}for(int i=17-1;i>=0;i--){if(dep[f[u][i]]>=dep[v])u=f[u][i];}if(u==v)return v;for(int i=16;i>=0;i--){if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}}return f[u][0];
}
void sign_up(int v,int fa)
{for(int u:e[v]){if(u!=fa){sign_up(u,v);dif[v]+=dif[u];}}ans=max(ans,dif[v]);
}
signed main()
{cin>>n>>k;for(int i=1;i<n;i++){cin>>u>>v;e[u].push_back(v);e[v].push_back(u);}dfs(1,0);for(int i=1;i<=k;i++){cin>>u>>v;dif[u]++;dif[v]++;dif[lca(u,v)]--;dif[f[lca(u,v)][0]]--;}sign_up(1,0);cout<<ans;return 0;
}

P3398 仓鼠找 sugar

归根到底,其实还是最近公共祖先的思想,但是我们这道题要想清楚的是,我们如何判断有两条路径相交,一方面是如果两条路径相交,那么第一条路径的公共祖先一定会在第二条路径上,但是我们如何去判断一个点在一个路径上,因此我们需要用到深度数组,如果其公共祖先在a,b这条路径上,那么a~公共祖先的距离+b~公共祖先的距离=a~b的距离

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,q;
int u,v;
vector<int> e[100005];
int dep[100005];
int f[100005][18];
void dfs(int v,int fa)
{dep[v]=dep[fa]+1;f[v][0]=fa;for(int i=1;i<18;i++){f[v][i]=f[f[v][i-1]][i-1];}for(int u:e[v]){if(u!=fa){dfs(u,v);}}
}
int lca(int u,int v)
{if(dep[u]<dep[v])swap(u,v);for(int i=17;i>=0;i--){if(dep[f[u][i]]>=dep[v])u=f[u][i];}if(u==v)return v;for(int i=17;i>=0;i--){if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}}return  f[u][0];
}
int dis(int u,int v)
{int LCA=lca(u,v);return abs(dep[u]-dep[LCA])+abs(dep[LCA]-dep[v]);
}
signed main()
{cin>>n>>q;for(int i=1;i<n;i++){cin>>u>>v;e[u].push_back(v);e[v].push_back(u);}dfs(1,0);int a,b,c,d;for(int i=1;i<=q;i++){cin>>a>>b>>c>>d;int x=lca(a,b),y=lca(c,d);if((dis(a,y)+dis(b,y)==dis(a,b))||(dis(c,x)+dis(d,x)==dis(c,d)))cout<<"Y\n";elsecout<<"N\n";}return 0;
}

这篇关于树章节习题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1105714

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

第六章习题11.输出以下图形

🌏个人博客:尹蓝锐的博客 希望文章能够给到初学的你一些启发~ 如果觉得文章对你有帮助的话,点赞 + 关注+ 收藏支持一下笔者吧~ 1、题目要求: 输出以下图形

【C++ Primer Plus习题】12.2

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "String.h"using namespace std;int main(){String s1(" and I am a

c++习题30-求10000以内N的阶乘

目录 一,题目  二,思路 三,代码    一,题目  描述 求10000以内n的阶乘。 输入描述 只有一行输入,整数n(0≤n≤10000)。 输出描述 一行,即n!的值。 用例输入 1  4 用例输出 1  24   二,思路 n    n!           0    1 1    1*1=1 2    1*2=2 3    2*3=6 4

C语言程序与设计第四版课后习题 - 1~8章大合集

前言 本文章是一个大合集,按照课后习题的命名方式命名,方便寻找,只需要在目录上点相对应的题号即可在这里插入图片描述 第一章课后习题 1.1 编写一个C程序 题目概述: 请参照本章例题,编写一个C程序,输出一下信息: *****************************Very good!***************************** 代码实现: #define

【C++ Primer Plus习题】12.1

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "Cow.h"using namespace std;int main(){Cow c1;Cow c2("老母牛", "喝奶"

应届生入职练手习题-蒙特卡洛算法(1.5H)

应届生入职练手习题 [编辑] 模拟射击,根据命中概率来求PI 要求:假设有一个半径为1000的圆形靶子(具体单位没有意义,不用写),我们随意对其进行射击,那么,统计所有落在圆形外接正方形中的弹着点,可以很容易得知:命中这个圆形靶子的概率是圆形的面积与外接方形面积的比 目的:检验编程风格和实现效率 要解这个题目就得有对蒙特卡洛算法的了解,原理如下 在数值积分法中,利用求单位圆的1/4的面积

软考-软件设计师(UML习题)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨   前言 小郑正在备考2024年下半年的中级软件设计师,所以打算开展一个软考备考专栏,在这里记录一下备

25版王道数据结构课后习题详细分析 第八章 8.2 插入排序

一、单项选择题 ———————————————————— ———————————————————— 解析:直接插入排序在最坏的情况下要做n(n-1)/2次关键字的比较,当n=5时, 关键字的比较次数为10。注意不考虑与哨兵的比较。 正确答案: ———————————————————— ———————————————————— 解析:由于序列初始基本有序,因此使用直接插入排序

栈和队列的习题详解(3):用栈实现队列

前言:   小编在上一篇博客中写过了用队列实现栈的操作,可能很多读者朋友会好奇用两个栈是否可以实现队列呢》这是当然可以的,下面小编将要讲述用栈实现队列这个习题,废话不多说,开始今天的做题之旅~ 目录 1.用栈实现队列 1.1.题干的解读 1.2.题目的解题思路 1.3.队列的功能实现  1.3.1.队列的初始化(MyQueue* myQueueCreate())   1.3