题目大意:

给定一颗黑白树.允许删除一个白点.最大化删点后无法与删点前距自己最远的黑点连通的黑点个数.并求出方案数.

题解:

这道题很棒棒啊.

一开始想了一个做法,要用LCT去搞,特别麻烦而且还是\(O(nlogn)\)的

% 了vfk的题解才知道这道题居然是\(O(n)\)的...


我们有一个结论:一个点到其最远点的路径一定经过树的直径的重心.

因为所有直径的重心一定相同,所以我们知道重心最多有两个,并且一定连续.

所以我们将重心提至根,以新的根重新建树.那么我们现在就可以发现我们要切断的所有路径一定都经过根.

所以我们考虑枚举删除的白点.其子树当中的所有黑点所连出的路径一定都被切断

那么我们现在考虑计算除这些子树外的路径.

对于同处于根的同一个儿子中的其他的黑点一定无法被切断.

这时我们要讨论一下我们当前的枚举点是否处于到根路径前2大的黑点所在的路径.

如果是,那么我们仍需要讨论一下这个路径是否全由这个以这个点为根的子树更新来.

然后再瞎XX判一些东西即可.(不具体说是什么是因为说不清楚...还不懂的话自己YY吧)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
struct Edge{
int to,next,dis;
}G[maxn<<1];
int head[maxn],cnt,rt;
void add(int u,int v,int d){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
G[cnt].dis = d;
}
bool col[maxn];
int f[maxn],g[maxn],pos;
#define v G[i].to
void dfs(int u,int f,int *dis){
if(col[u] && dis[pos] < dis[u]) pos = u;
for(int i = head[u];i;i=G[i].next){
if(v == f) continue;
dis[v] = dis[u] + G[i].dis;
dfs(v,u,dis);
}
}
int belong[maxn],siz[maxn];
void dfs2(int u,int fa,int d){
if(fa == rt) belong[u] = u;
else belong[u] = belong[fa];
siz[u] = col[u];
for(int i = head[u];i;i=G[i].next){
if(v == fa) continue;
dfs2(v,u,d+G[i].dis);
siz[u] += siz[v];
}
if(siz[u]){
f[u] = d;g[u] = 1;
for(int i = head[u];i;i=G[i].next){
if(v == fa) continue;
if(f[v] > f[u]){
f[u] = f[v];
g[u] = g[v];
}else if(f[v] == f[u]) g[u] += g[v];
}
}
}
#undef v
int main(){
int n,m;read(n);read(m);
for(int i=1,x;i<=m;++i){
read(x);col[x] = true;
}
for(int i=1,u,v,d;i<n;++i){
read(u);read(v);read(d);
add(u,v,d);add(v,u,d);
}
pos = 0;dfs(1,1,f);
int x = pos;pos = 0;
dfs(x,x,g); memset(f,0,sizeof f);
dfs(pos,pos,f);
rt = 0;
for(int i=1;i<=n;++i){
if(f[i] + g[i] == f[x]){
if(rt == 0) rt = i;
else if(abs(f[i] - g[i]) < abs(f[rt] - g[rt])) rt = i;
}
}
memset(f,0,sizeof f);
memset(g,0,sizeof g);
dfs2(rt,rt,0);
int mx = 0,cmx = 0,mxid = 0,cmxid = 0;
for(int i = head[rt];i;i=G[i].next){
int v = G[i].to;
if(siz[v] == 0) continue;
if(f[v] > mx){
cmx = mx;cmxid = mxid;
mx = f[v];mxid = v;
}else if(f[v] == mx){
if(mx == cmx){
mxid = cmxid = 0;
break;
}else{
cmx = mx;cmxid = mxid;
mx = f[v];mxid = v;
}
}else if(f[v] > cmx){
cmx = f[v];
cmxid = v;
}
}
int ans = 0,ans_cnt = 0;
if(col[rt] == false) ans = m,ans_cnt = 1;
for(int i = 1;i<=n;++i){
if(i == rt || col[i]) continue;
int res = siz[i];
if(siz[i]&&(f[i] == f[belong[i]])&&(g[i] == g[belong[i]])){
if(belong[i] == mxid){
if(f[mxid] > f[cmxid]) res += m - siz[mxid];
else res += siz[cmxid];
}else if(belong[i] == cmxid) res += siz[mxid];
}
if(res > ans) ans = res,ans_cnt = 1;
else if(res == ans) ++ ans_cnt;
}
printf("%d %d\n",ans,ans_cnt);
return 0;
}

uoj problem 11 ydc的大树的更多相关文章

  1. uoj problem 10

    uoj problem 10 题目大意: 给定任务若干,每个任务在\(t_i\)收到,需要\(s_i\)秒去完成,优先级为\(p_i\) 你采用如下策略: 每一秒开始时,先收到所有在该秒出现的任务,然 ...

  2. Problem 11

    Problem 11 # Problem_11.py """ In the 20×20 grid below, four numbers along a diagonal ...

  3. 【UTR #1】ydc的大树

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

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

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

  5. UOJ #11 - 【UTR #1】ydc的大树(换根 dp)

    题面传送门 Emmm--这题似乎做法挺多的,那就提供一个想起来写起来都不太困难的做法吧. 首先不难想到一个时间复杂度 \(\mathcal O(n^2)\) 的做法:对于每个黑点我们以它为根求出离它距 ...

  6. leetcode problem 11 Container With Most Water

    Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). ...

  7. uoj problem 31 猪猪侠再战括号序列

    题目大意: 给定一个长度为2n的括号序列.定义一个关于区间[l,r]的翻转操作为位置平移对调. 即翻转")))()("可以得到"()()))((" 用不超过n次 ...

  8. uoj problem 14 DZY Loves Graph

    题目: DZY开始有 \(n\) 个点,现在他对这 \(n\) 个点进行了 \(m\) 次操作,对于第 \(i\) 个操作(从 \(1\) 开始编号)有可能的三种情况: Add a b: 表示在 \( ...

  9. uoj problem 21 缩进优化

    题目: 小O是一个热爱短代码的选手.在缩代码方面,他是一位身经百战的老手.世界各地的OJ上,很多题的最短解答排行榜都有他的身影.这令他感到十分愉悦. 最近,他突然发现,很多时候自己的程序明明看起来比别 ...

随机推荐

  1. Mysql 行数据转换为列数据

    现有如下表: 需要统计手机所有售卖价格,显示为如下表: 需要使用group_concat对price进行处理,并且去重重复价格 sql如下: select type,group_concat(DIST ...

  2. mybatis 视频总结

    [说明]mabatis卡住了,理解的不深,配置文件的格式太多看不懂(除了连接数据库的部分),听说还可以和log4j集成,怎么个方法 一:今日完成 1)一些语言细节和操作细节 比如在servlet里面操 ...

  3. Zookeeper数据与存储

    一.前言 前面分析了Zookeeper对请求的处理,本篇博文接着分析Zookeeper中如何对底层数据进行存储,数据存储被分为内存数据存储于磁盘数据存储. 二.数据与存储 2.1 内存数据 Zooke ...

  4. unity里standard pbr(一)

    关注forwardbase下的 standard.shader #pragma vertex vertBase #pragma fragment fragBase #include "Uni ...

  5. PAT 1061. 判断题(15)

    判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分. 输入格式: 输入在第一行给出两个不超过100的正整数N和M,分别是学生人数和判断题数量.第二行给出M个不超过5的正 ...

  6. lzugis—搭建属于自己的小型的版本号控制SVN

    版权声明:本文为LZUGIS原创文章,未经同意不得转载. https://blog.csdn.net/GISShiXiSheng/article/details/28643575 对于不了解SVN的同 ...

  7. LeetCode:反转字符串中的元音字母【345】

    LeetCode:反转字符串中的元音字母[345] 题目描述 编写一个函数,以字符串作为输入,反转该字符串中的元音字母. 示例 1: 输入: "hello" 输出: "h ...

  8. gitlab-jenkins安装

    由于公司发布预览版比较麻烦,于是准备使用 jenkins + gitlab 做一个自动化部署的工具,这里记录一下在公司本地 CentOS 服务器上安装 Jenkins 和 gitlab. 配置 jav ...

  9. python中reduce()函数

    reduce()函数也是Python内置的一个高阶函数.reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收 ...

  10. web框架详解之tornado 一 模板语言以及框架本质

    一.概要 Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过 ...