博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
uoj problem 11 ydc的大树
阅读量:5266 次
发布时间:2019-06-14

本文共 2725 字,大约阅读时间需要 9 分钟。

题目大意:

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

题解:

这道题很棒棒啊.

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

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


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

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

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

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

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

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

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

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

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

#include 
#include
#include
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].tovoid 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 vint 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
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;}

转载于:https://www.cnblogs.com/Skyminer/p/6636850.html

你可能感兴趣的文章
Linux 进程资源用量监控和按用户设置进程限制
查看>>
IE浏览器整页截屏程序(二)
查看>>
D3.js 之 d3-shap 简介(转)
查看>>
制作满天星空
查看>>
类和结构
查看>>
CSS3选择器(二)之属性选择器
查看>>
adidas crazylight 2018 performance analysis review
查看>>
typeset shell 用法
查看>>
python 之 循环语句
查看>>
心得25--JDK新特性9-泛型1-加深介绍
查看>>
[转]ceph网络通信模块_以monitor模块为例
查看>>
HDOJ 1754 I Hate It(线段树基本操作)
查看>>
latex tree
查看>>
安装NVIDIA驱动时禁用自带nouveau驱动
查看>>
HDU-1255 覆盖的面积 (扫描线)
查看>>
css3学习01
查看>>
【USACO】 奶牛会展
查看>>
继承和多态
查看>>
Dijkstra+计算几何 POJ 2502 Subway
查看>>
修复IE不能执行JS的方法
查看>>