题目传送门

题目大意: 给一棵由黑白点组成的树,如果一个黑点无法到达所有离他最远的点,他就会不开心,问有多少种方式使得删掉一个白点后不开心的黑点数最大。

题解

首先这题用到一个结论:树上任意一点到离他最远的点的路径一定经过树的中心(不是重心),那么对于这题,我们就可以先找到树的中心,将它定为树根,这样可以保证每条到最远点的路径都经过根。

我们都知道,找树的中心要先找树的直径,因为这题只有黑点要找最远的黑点,所以我们找直径时只看黑点,不看白点,具体代码是这样的:

//应该都知道找直径是要两次dfs找最远点的吧qwq,但还是有必要提一下
void dfs1(int x,int fa,int *dis)//dis数组记录每个点到出发点的距离
{if(dis[x]>dis[furt])furt=x;//furt即furthest,记录离出发点最远的黑点for(int i=first[x];i;i=e[i].next){int y=e[i].y; if(y==fa)continue;dis[y]=dis[x]+e[i].z; dfs1(y,x,dis);}
}

主函数中就是这么一小段:

dfs1(1,0,a); a[furt]=0; dfs1(furt,0,a);

接下来枚举每一个白点,统计将它删除后有多少个不高兴的黑点。以及为了方便,这里做个定义:如果一个点 xxx 在根的儿子 yyy 的子树内,那么设 top[x]=ytop[x]=ytop[x]=y。

由于我们将中心定成了根,那么对于任意一个黑点 xxx,离他最远的黑点就是不在 top[x]top[x]top[x] 的子树内的离根最远的黑点,于是我们需要统计一下,根的每个儿子的子树内离根最远的黑点到根的距离以及数量。

另外,我们还需要统计出所有黑点中离根最远的是在哪个儿子的子树中,最远的记为 ma1ma1ma1,次远的记作 ma2ma2ma2,有可能有两个儿子都含有最远黑点,但如果有三个或以上的儿子含有最远黑点,就会发现,删掉任意一个白点后,只有这个白点内的黑点会不高兴,一定不会影响到其它黑点。

以及,删去一个白点 xxx 后,在 top[x]top[x]top[x] 的子树内的且不在 xxx 子树内的黑点一定不受影响。

接下来就是分类讨论了,分类讨论这部分配合代码食用更佳:

for(int i=1;i<=n;i++)//枚举白点
{if(col[i]||i==root)continue;int ans_=black[i];//black[i]表示i的子树内黑点的个数,显然,将i删去后它子树内的黑点一定都会不高兴//下面就是统计子树外的黑点有多少个会不高兴,不高兴的前提是那个黑点的所有最远点都在i的子树内if(black[i]&&a[i]==a[top[i]]&&b[i]==b[top[i]])//对black[i]的判断大家都懂,后面判断的是在top[i]的子树内离根最远的黑点是否都在i的子树内//如果不是,那么删去i后对其它的黑点肯定都没有影响,这个想想就能明白{if(top[i]==ma1)//假如top[i]的子树内有最远黑点{if(a[ma1]==a[ma2])ans_+=black[ma2];//假如最远和次远一样远,那么删去i后只有次远的整棵子树会到不了离他们最远的黑点else ans_+=m-black[ma1];//假如最远比次远要远,那么除了最远的这棵子树,其他点都会受影响}else if(top[i]==ma2)ans_+=black[ma1];//如果是次远,那么只有最远会受影响}if(ans_>ans)ans=ans_,anss=1;//更新答案else if(ans_==ans)anss++;
}

完整代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100010int n,m,col[maxn];
struct edge{int y,z,next;};
edge e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y,int z)
{e[++len]=(edge){y,z,first[x]};first[x]=len;
}
int a[maxn],b[maxn],furt=1;
void dfs1(int x,int fa,int *dis)//找离出发点最远的点
{if(dis[x]>dis[furt])furt=x;for(int i=first[x];i;i=e[i].next){int y=e[i].y; if(y==fa)continue;dis[y]=dis[x]+e[i].z; dfs1(y,x,dis);}
}
int abs(int x){return x<0?-x:x;}
int black[maxn],top[maxn],root=0;
void dfs2(int x,int fa,int dis)//统计每个点子树内的黑点数以及最远的黑点
{if(fa==root)top[x]=x; else top[x]=top[fa];black[x]=col[x]; if(col[x])a[x]=dis,b[x]=1;for(int i=first[x];i;i=e[i].next){int y=e[i].y; if(y==fa)continue;dfs2(y,x,dis+e[i].z);if(a[y]>a[x])a[x]=a[y],b[x]=b[y];else if(a[y]==a[x])b[x]+=b[y];black[x]+=black[y];}
}int main()
{scanf("%d %d",&n,&m);for(int i=1,x;i<=m;i++)scanf("%d",&x),col[x]=1;for(int i=1,x,y,z;i<n;i++)scanf("%d %d %d",&x,&y,&z),buildroad(x,y,z),buildroad(y,x,z);dfs1(1,0,a);a[furt]=0; int p=furt;dfs1(furt,0,a); dfs1(furt,0,b);for(int i=1;i<=n;i++){if(a[i]+b[i]==b[p])//假如该点在直径上{if(root==0)root=i;//并且这个点更靠近中点,就更新树的中心else if(abs(a[i]-b[i])<abs(a[root]-b[root]))root=i;}}memset(a,0,sizeof(a));memset(b,0,sizeof(b));dfs2(root,0,0);int ma1=0,ma2=0;for(int i=first[root];i;i=e[i].next){int y=e[i].y; if(!black[y])continue;if(a[y]>a[ma1])ma2=ma1,ma1=y;//找最远和次远else if(a[y]>a[ma2])ma2=y;}for(int i=first[root];i;i=e[i].next)//假如有三个一样的最远,那么一定不会影响子树外的点if(e[i].y!=ma1&&e[i].y!=ma2&&a[e[i].y]==a[ma1]){ma1=ma2=0;break;}int ans=0,anss=0;if(!col[root])ans=m,anss=1;//统计根的答案for(int i=1;i<=n;i++){if(col[i]||i==root)continue;int ans_=black[i];if(black[i]&&a[i]==a[top[i]]&&b[i]==b[top[i]]){if(top[i]==ma1){if(a[ma1]==a[ma2])ans_+=black[ma2];else ans_+=m-black[ma1];}else if(top[i]==ma2)ans_+=black[ma1];}if(ans_>ans)ans=ans_,anss=1;else if(ans_==ans)anss++;}printf("%d %d",ans,anss);
}

UOJ #11.【UTR #1】ydc的大树 题解相关推荐

  1. 【UTR #1】ydc的大树

    [UTR #1]ydc的大树 全网唯一一篇题解我看不懂 所以说一下我的O(nlogn)做法: 以1号点为根节点 一个黑点如果有多个相邻的节点出去都能找到最远的黑点,那么这个黑点就是无敌的 所以考虑每个 ...

  2. UOJ #11. 【UTR #1】ydc的大树

    题目描述: ydc有一棵n个结点的黑白相间的大树,从1到n编号. 这棵黑白树中有m个黑点,其它都是白点. 对于一个黑点我们定义他的好朋友为离他最远的黑点.如果有多个黑点离它最远那么都是它的好朋友.两点 ...

  3. [树的直径 树形DP] UOJ #11【UTR #1】ydc的大树

    题解链接 大意是我们求出直径的中心 那么到最远点必然经过中心 把它提到根 就可以在枚举删的白点时很快统计出能够使多少个黑点不高兴 #include<cstdio> #include< ...

  4. uoj problem 11 ydc的大树

    题目大意: 给定一颗黑白树.允许删除一个白点.最大化删点后无法与删点前距自己最远的黑点连通的黑点个数.并求出方案数. 题解: 这道题很棒棒啊. 一开始想了一个做法,要用LCT去搞,特别麻烦而且还是\( ...

  5. UOJ 【UR #4】追击圣诞老人 题解

    题目传送门 题目大意: 生蛋老人要找前 kkk 条最短路,生蛋老人可以在节点之间飞跃但是有某些限制,到达一个节点 xxx 就要停 w[x]w[x]w[x] 秒,节点可以重复经过. 题解 新题解传送门 ...

  6. 11.13蓝桥杯选拔赛热身赛题解——HH的LCM

    基础算法...求两个整数的最小公倍数.先求一下最大公约数,然后就能求最小公倍数啦. import java.util.*; public class HH的LCM {public static int ...

  7. 算法题-----题目、题解、个人算法、个人思考

    算法题-----题目.题解.个人算法.个人思考,项目说明]这里记录算法题目,这里记录:算法题目简单描述,暂存对于这道题的SK_cache(自己的卡点.自己的思路.自己对这道题的理解,自己的疑问.自己对 ...

  8. 2020年 第11届 蓝桥杯 Java B组 省赛真题详解及小结【第2场省赛 2020.10.17】

    蓝桥杯 Java B组 省赛真题详解及小结汇总[2013年(第4届)~2020年(第11届)] 说明:大部分题解思路及程序代码 源自 蓝桥杯 官网视频(Java B组历年真题解析) -- 郑未老师. ...

  9. [SDOI2011]染色 (线段树维护子段问题+树剖)

    题意: 给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种: 1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c. 2.询问节点 a 到节点 b 的路径上的颜色段 ...

最新文章

  1. 2018-2019-1 20165318《信息安全系统设计基础》第八周课上测试
  2. Office 2010默认输入法设置方法
  3. 学习java时的一些笔记(4)
  4. JVM参数调优,无停滞实践
  5. pokemon 下载 android,宝可梦pokemon home
  6. Android短视频中如何实现720P磨皮美颜录制?
  7. 【源码分析】storm拓扑运行全流程源码分析
  8. 贵州2021高考体考成绩查询,2021年贵州体育专业考试成绩查询网址:http://www.eaagz.org.cn/...
  9. [剑指offer]面试题8:旋转数组的最小数字
  10. 春天重试,因为冬天来了
  11. sql:MySQL 6.7 表,视图,存储过程结构查询
  12. 腾讯、阿里能像 Facebook 一样发币吗?
  13. django实现搜索功能
  14. 联想电脑锁屏界面设置被组织隐藏_Word Clock数字时钟动态屏保,让你的电脑锁屏瞬间科技感十足!...
  15. Shared File System Master Slave 全配置以及测试
  16. python和java md5加密,如何将javamd5加密代码移植到Python中?
  17. 今日头条的针锋相对让腾讯开始焦虑,天天快报能否占据一席之位?
  18. 计算机组成bcd码,bcd码怎么换算(8421bcd码计算器)
  19. 【备忘】尚学堂白贺翔java互联网架构师视频教程下载
  20. 3D全景图php代码,HTML5 Canvas实现360度全景图的示例代码

热门文章

  1. fastdfs连接mysql_使用fastdfs-zyc监控FastDFS文件系统
  2. 联想第二季度业绩创纪录 所有业务实现强劲增长
  3. 全球首位亿万富豪上太空!
  4. UG二次开发装配篇 添加/拖动/删除组件方法的实现
  5. 【推荐系统】User-Item CF:GC-MC
  6. mysql 插入缓冲_innodb insert buffer 插入缓冲区的理解
  7. 9.9的阿里巴巴编码规范考试竟如此简单?搜集试题分享!让我们一起守护开发规范!
  8. 利用Excel饼图画出八等份圆
  9. 注意:网站中出现以下违规内容-搜索引擎百度都不收录
  10. 关于三方支付做的一个小总结,后期不断完善更新