第三次发题解哈。有什么表述错误的请见谅(可以提出)。

题目源地址:https://www.lydsy.com/JudgeOnline/problem.php?id=1776

文章目录

  • 题目描述
  • 输入
  • 输出
  • 样例输入
  • 样例输出
  • 附图
  • 优化!LCA!
  • 优化!枚举!
  • 优化!计算!
  • 代码

题目描述

农夫约翰的奶牛住在N (2 <= N <= 200,000)片不同的草地上,标号为1到N。恰好有N-1条单位长度的双向道路,用各种各样的方法连接这些草地。而且从每片草地出发都可以抵达其他所有草地。也就是说,这些草地和道路构成了一种叫做树的图。输入包含一个详细的草地的集合,详细说明了每个草地的父节点P_i (0 <= P_i <= N)。根节点的P_i == 0, 表示它没有父节点。因为奶牛建立了1到K一共K (1 <= K <= N/2)个政党。每只奶牛都要加入某一个政党,其中, 第i只奶牛属于第A_i (1 <= A_i <= K)个政党。而且每个政党至少有两只奶牛。 这些政党互相吵闹争。每个政党都想知道自己的“范围”有多大。其中,定义一个政党的范围是这个政党离得最远的两只奶牛(沿着双向道路行走)的距离。 比如说,记为政党1包含奶牛1,3和6,政党2包含奶牛2,4和5。这些草地的连接方式如下图所 示(政党1由-n-表示): 政党1最大的两只奶牛的距离是3(也就是奶牛3和奶牛6的距离)。政党2最大的两只奶牛的距离是2(也就是奶牛2和4,4和5,还有5和2之间的距离)。 帮助奶牛们求出每个政党的范围。

输入

  • 第一行: 两个由空格隔开的整数: N 和 K * 第2到第N+1行: 第i+1行包含两个由空格隔开的整数: A_i和P_i

输出

  • 第1到第K行: 第i行包含一个单独的整数,表示第i个政党的范围。

样例输入

6 2
1 3
2 1
1 0
2 1
2 1
1 5

样例输出

3
2

附图


身为蒟蒻,对这一题的意思还是斟酌了很久的。给大家讲一下题面:
输入
1:读入n和k,表示这棵树由几个点组成和有多少个政党。
2~n+1:读入A_i和P_i,表示点i属于第A_i个政党的势力范围内(暂且就这么叫吧)并给出父节点P_i。
输出
1~k:输出每个政党的势力范围。

势力范围事实上是解这题的关键突破口,题面中给这个词语的解释换句话来说就是要在树上找同政党中相隔距离最远的两点。而这个距离怎么去确定?我给大家打个比方,一条Y字形道路,我们要确定“Y”字任意两端点的距离,就应该计算这两个端点与中间一点的距离和,而这中间一点就是我们今天要讨论的LCA(最近公共祖先)

  1. 目的
    顾名思义,LCA要求的就是树上两点的最近公共祖先,有两层含义:
    ①:公共祖先:这个意思不难理解,就是类似于两条街的分岔口,例如好比一棵树的根节点是所有节点的祖先(PS:LCA可以是两个点中的任意一点,类似于求最小公倍数)
    ②:最近:既是公共祖先,又必须离两个点最近。

  2. 实现
    一般来讲我们应该讲树上的两个结点想象成两个动点,首先得让他们“移动”到同一深度处,然后每个点都同时向上移动一次,最后重合的点即为他们的公共祖先,但是很显然,题目中的数据过大(上述算法时间复杂度为O(n2)),之后还要进行枚举,若依然按照原始方法——O(n3)那无疑是一个可怕的时间量,偏偏这一题的时间限制只有1000ms。

优化!LCA!

我们又见到了老朋友(如果你总是看我的博客的话就会记忆深刻),也就是RMQ思想,在这里就不细讲了,有兴趣的神犇们可以去这个网址https://blog.csdn.net/weixin_44613722/article/details/86615493也是本人的一篇蒟蒻题解,讲的比较详细(jianlou)。当然这个rmq思想也可以用i的n次方而不仅仅是2的n次方(n为非负整数)来分割,但是考虑到2n较容易理解,且任何数都能用不重复的单项式(2n)组成的多项式来表达(这样要快一些,可以少几次循环)。在这里我们给出一些例子:

其实这个道理很简单解释,通俗点讲就是一分为二,初中应该就学过这个公式:20+21+22+23+…+2n=2n+1
好的不扯了我们具体讲讲如何优化:

  1. 原来我们是每一个点移动一次,但其实我们可以每一个点都移动2n次,在这里我们要定义一个二维数组
    f[i][j]表示在点i向上跳2j次所到达的地方,同样我们可以得出:
f[i][j]=f[f[i][j-1]][j-1]或者是f[i][j]=f[i+1<<(j-1)][j-1]
  1. 我们可以做一个逆循环枚举一下j,因为如果做正循环从小到大做你无法知道在这个时候符合要求(保证两点仍在一棵子树的左右两侧,,因为我们没办法确定两点所跳到的某个祖先是最近的)的情况下所能跳的最多步数。
  2. 实际解决问题当中可能一开始两点都在一棵子树的两侧,那么这样的话LCA当然就是深度小的那个点,我们可以加一个判断条件,如果当两点跳至同一深度时,检测两点的标号是否一致,若一致则返回任意一点的标号。
  3. 我们还要注意的一点是:当两点已经不能再跳时(就是一步也跳不上去的时候,因为跳一步就到了同一个点,也就是祖先点),这个时候就说明这两点的父亲点就是原先要求的两点的最近公共祖先。
  4. 代码如下O(nlogn):
int lca(int x,int y)
{if(dep[x]<dep[y])swap(x,y);//如果x的深度小于y,就交换一下,便于后面的操作for(int i=20;i>=0;i--)//2的20次方大概有一百万了,这一题的数据只有二十万if(dep[f[x][i]]>=dep[y])x=f[x][i];//将两点处理到同一深度if(x==y)return x;//点3所阐述的情况for(int i=20;i>=0;i--){if  (f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];}return f[x][0];//x或y的父亲点就是原先两点的最近公共祖先
}

优化!枚举!

其实原先就有过暗示这一步肯定是有优化的,暴力做法是把同一个政党的点全部统计出来,两两做一次LCA,但实际上来说我们可以确定其中一个点(这个点是深度最深的那个点),但不能确定两个点,因为距离是相对来说的,并不是深度越大的两点距离越远,例如一颗满二叉树最深的两点且它们的父亲点就是他们的最近公共祖先,深度是相对于根节点而言的,所以只能确定一个点而剩下的那个点只能靠枚举。确定最深的点应该就不需要本蒟蒻赘言了吧…时间复杂度为O(n2)

优化!计算!

照引言上的说法,我们要计算LCA与两点的距离和,一般人可能会从LCA开始做一个dfs去找那两点并计算(各位神犇大佬请不要喷我),但其实我们没必要这样我们可以拿两点的深度和减去两倍的LCA深度,用画图来表示大概就是这样:

比方说我们要求8和10的距离(其LCA为2),LCA的深度已被我们用红色部分表示,其余两点的深度被黑色部分表示,所以(dis数组是距离的意思,dep数组是深度的意思)dis[1…8]-dis[1…2]=dis[2…8],dis[1…10]-dis[1…2]=dis[2…10].由于我们要求的是dis[2…8]+dis[2…10],所以可以替换为dis[1…8]+dis[1…10]-2×dis[1…2],经过推算我们可以发现dis[1…n]=dep[n]-1
所以计算出来就是(dep[8]-1)+(dep[10]-1)-2×(dep[2]-1),化简得dep[8]+dep[10]-2×dep[2].
所以对于任意两点x,y则它们的距离为dep[x]+dep[y]-2×dep[lca(x,y)].

代码

代码有些丑,别嫌弃…

#include <bits/stdc++.h>
using namespace std;
int n,k,ai,pi,tot,rt;
int pre[400001],son[400001],now[400001],zd[400001],dep[400001],dest[200001],desti[200001],f[400001][21],Ans[200001];void put(int x,int y)//建立边表
{pre[++tot]=now[x];now[x]=tot;son[tot]=y;
}
void dfs(int u,int deep)
{dep[u]=deep;for(int i=now[u];i;i=pre[i]){f[son[i]][0]=u;dfs(son[i],deep+1);}
}
int lca(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];if(x==y)return x;for(int i=20;i>=0;i--){if  (f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];}return f[x][0];
}
int main()
{scanf("%d%d",&n,&k);for(int i=1;i<=n;i++){scanf("%d%d",&ai,&pi);put(pi,i);if(pi==0)rt=i;zd[i]=ai;}dfs(rt,1);for(int i=1;i<=20;i++){for(int j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1];}for(int i=1;i<=n;i++)//检测每个政党深度最大的一点{if  (dep[i]>dest[zd[i]]){dest[zd[i]]=dep[i];//dest记录深度desti[zd[i]]=i;//desti记录标号}}for(int i=1;i<=n;i++)Ans[zd[i]]=max(Ans[zd[i]],dest[zd[i]]+dep[i]-2*dep[lca(desti[zd[i]],i)]);for(int i=1;i<=k;i++)printf("%d\n",Ans[i]);return 0;
}

如有什么不足之处,还请各位神犇指导。

[Usaco2010 Hol]cowpol 奶牛政坛(入门oj Problem 5274)相关推荐

  1. COGS——T 803. [USACO Hol10] 政党 || 1776: [Usaco2010 Hol]cowpol 奶牛政坛

    http://www.lydsy.com/JudgeOnline/problem.php?id=1776||http://cogs.pro/cogs/problem/problem.php?pid=8 ...

  2. [Usaco2010 Hol]cowpol 奶牛政坛

    题目描述: 农夫约翰的奶牛住在N (2 <= N <= 200,000)片不同的草地上,标号为1到N.恰好有N-1条单位长度的双向道路,用各种各样的方法连接这些草地.而且从每片草地出发都可 ...

  3. BZOJ1776: [Usaco2010 Hol]cowpol 奶牛政坛

    n<=100000个点的树,每个点属于一个K<=n/2个集合中的一个,每个集合至少两个点,求每个集合中任选两点距离的最大值. 方法一:什么都看不出来,点分,每次只统计经过一个点的每个集合的 ...

  4. [usaco2010 Oct]Soda Machine (入门oj Problem 6195 )

    鬼知道我有多蒟蒻,第五次发题解了 题目原地址点此进入 呜呜呜~今天在CSDN上看了好多大佬神犇的OI退役文,百感交集,故写篇题解振奋自己. 文章目录 题目描述 输入 输出 样例输入 样例输出3 题目大 ...

  5. BZOJ 1779. [Usaco2010 Hol]Cowwar 奶牛战争

    传送门 考虑构建网络流模型 把一个流量看成一只奶牛的攻击过程,那么答案就是最大流 因为每只奶牛只能操作一波,所以构造分层图,一层相当于一步 第一层就是初始状态,从 $S$ 向所有 $J$ 奶牛连一条流 ...

  6. 【BZOJ1778】[Usaco2010 Hol]Dotp 驱逐猪猡 期望DP+高斯消元

    [BZOJ1778][Usaco2010 Hol]Dotp 驱逐猪猡 Description 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 300 ...

  7. BZOJ_1778_[Usaco2010 Hol]Dotp 驱逐猪猡_概率DP+高斯消元

    BZOJ_1778_[Usaco2010 Hol]Dotp 驱逐猪猡_概率DP+高斯消元 题意: 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 3 ...

  8. [BZOJ 1778][Usaco2010 Hol]Dotp 驱逐猪猡

    1778: [Usaco2010 Hol]Dotp 驱逐猪猡 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 690  Solved: 269 [Sub ...

  9. [Usaco2010 Mar]gather 奶牛大集会

    1827: [Usaco2010 Mar]gather 奶牛大集会 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 1129  Solved: 525 [ ...

最新文章

  1. 终结由安装SVN 导致的异常——visual studio 2010 遇到了异常,可能是由某个扩展导致
  2. postfix+postfixadmin+extmail邮件服务器架设过程
  3. net读取exchange数据
  4. 用css、html编写一个两列布局的网页,名称为css.html ,要求左侧宽度为200px ,右侧自动扩展...
  5. 大会门票限免最后一周!来聊聊 NVIDIA、抖音等大厂的 AI 技术落地
  6. php代理请求失败,http请求失败有哪些原因
  7. 多核环境下pthread调度执行bthread的过程
  8. web前端开发最佳实践_Web开发人员和设计师的最佳黑色星期五优惠
  9. 一个有助于理解事件冒泡和事件捕获的例子
  10. vj p1038题解
  11. 图片命名html,网页切图div+css命名规则
  12. 不会写原创文章,在线洗稿软件能处理吗
  13. 地铁综合监控系统网络方案,简化工作轻松应对客流高峰
  14. elk学习中遇到的一些问题
  15. 如何解决 win10 2016Excel 显示界面全为英文的情况
  16. python基础教程怎么看_python基础教程之看一篇,学一篇,今日份的pand
  17. 刀片服务器在哪看cpu型号,了解认识刀片服务器
  18. 用php写的亲亲鲜花网站_PHP最新鲜花礼品商城网站整站源码(自适应手机端) 鲜花商城dedecms模板源码...
  19. Oracle的 listagg 函数,多行合并一行
  20. 慕的2021阅读数据分析报告

热门文章

  1. 【Lesson 1】 和弦 Chord
  2. 1.1 win10下wget的安装
  3. 关于台电X16 plus (Tpad)安装win10系统
  4. (NO.00004)iOS实现打砖块游戏(一):素材的制作
  5. STM32学习心得十九:电容触摸按键实验及相关代码解读
  6. 推荐一下十三款内网穿透工具(超全)
  7. 【PM学习笔记】酸梅干超人 - 零基础学Figma学习笔记
  8. 【Java】位运算符---算术右移和逻辑右移、算术左移和逻辑左移
  9. 关于中宣部实名认证过程中的一些问题和解答
  10. 高考倒计时100天....99天