2022.9.26 闲话 / Dijkstra No (B: htaaywaai)
因为一些原因所以早点发闲话,晚了就没机会发了 .
标题是一个解密
关于树的直径的一个结论(Anton and Tree)
题目描述
题目链接 .
给一棵 \(n\) 个节点的树,每个点为黑色或白色,一次操作可以使一个相同颜色的连通块变成另一种颜色,求使整棵树变成一种颜色的最少操作数 .
\(n\le 2\times 10^5\) .
解答(含详细证明)
首先把每个同色连通块缩成一个点,并查集实现是 \(O(n\alpha(n))\) 的,Tarjan 实现就是 \(O(n)\) 的 .
这样问题就可以变成:
Flood Fill
给一棵树 \(\mathcal T\),对于一个点 \(u\),其代价定义为 \(u\) 和 \(\mathcal T\) 上所有点距离之最大值 .
对于每个点 \(u\),问最小代价是多少 .
结论是满足条件的 \(u\) 就是直径的中点(如果直径长度是偶数那么有两个中点).
反证法,如果有一个 \(u'\) 是最优解:
-
如果 \(u'\) 不在树的直径上,于是贡献在直径端点上(这可以根据直径的定义得到),那么考察直径上随便一个点 \(u\) 可以发现 \(u'\) 一定不优于 \(u\) .
-
如果 \(u'\) 在直径上但不在中点上,假设 \(u'\) 的出点中离直径中点 \(m\) 最近的点是 \(u\),那么考虑以 \(u'\) 为根,\(u\) 的子树产生的贡献(不算直径上的点),这一定是比原来小的 .
可以通过反证法得知子树外产生的贡献一定是不如子树内的,于是 \(u'\) 不如 \(u\)(逐步调整就可以得到 \(m\) 才是最优的,但是这里是反证法所以没必要去说明这个).
把上面的证明的脚手架展示出来就比较显然明了了,因为我 so lazy 所以懒得画图了,可能有点晦涩 .
但是直径可能有很多啊,我们还需要证明所有直径的中点重合,不然上面的证明就是有点问题的 .
若树上所有边边权均为正,则树的所有直径中点重合 .
还是用反证法 . 令两条中点不重合的直径端点分别为 \((u_1,v_1)\),\((u_2,v_2)\),中点设为 \(m_1,m_2\) .
则 \(\operatorname{dist}(u_1,m_1)=\operatorname{dist}(m_1,v_1)=\operatorname{dist}(u_2,m_2)=\operatorname{dist}(m_2,v_2)\) .
那么 \(\operatorname{dist}(u_1,v_2)=\operatorname{dist}(u_1,m_1)+\operatorname{dist}(m_1,m_2)+\operatorname{dist}(m_2,v_1)>\operatorname{dist}(u_1,m_1)+\operatorname{dist}(m_1,v_1)=\operatorname{dist}(u_1,v_1)\) .
也就是说 \((u_1,v_2)\) 这条路径比 \((u_1,v_1)\) 更长,这与它是直径矛盾,所以直径中点必然重合 .
注:最后一步用的是三角形不等式,这也就限制了树上所有边边权均为正 .
完整代码
因为我不会两次 DFS 求树的直径所以用的树形 DP .
不要像我一样并查集不加路径压缩卡在 TLE #11 无法自拔 .
#include <bits/stdc++.h>
#define filein(x) {freopen(x".in", "r", stdin);}
#define file(x) {freopen(x".in", "r", stdin); freopen(x".out", "w", stdout);}
#define files(x) {freopen(x".in", "r", stdin); freopen(x".out", "w", stdout);}
template<typename T>
inline T chkmin(T& x, const T& y){if (x > y) x = y; return x;}
template<typename T>
inline T chkmax(T& x, const T& y){if (x < y) x = y; return x;}
template<typename T>
inline bool inrange(T x, T l, T r){return (l <= x) && (x <= r);}
template<typename T>
inline bool inrange(T l, T r, T L, T R){return (L <= l) && (r <= R);}
#define mem(x, a) memset(x, a, sizeof x);
#define cls(x) rep(x, 0)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
inline db sqr(const db& x){return x * x;}
template <typename T>
using pr = pair<T, T>;
typedef pr<int> pii;
typedef pr<ll> pll;
typedef pr<db> pdd;
typedef complex<double> cp;
typedef vector<int> vi;
const int N = 2e5 + 123;
struct dsu
{
int fa[N];
inline void reset(){iota(fa, fa+N, 0);}
dsu(){reset();}
int get(int x){return fa[x] = (x == fa[x]) ? x : get(fa[x]);}
inline void merge(int u, int v){fa[get(u)] = get(v);}
}B, W;
template<typename T>
class pool
{
unordered_map<T, unsigned> pol;
unsigned cc;
public:
pool(){cc = 0;}
~pool() = default;
unsigned get(T x)
{
auto ptr = pol.find(x);
if (ptr == pol.end()){pol[x] = ++cc; return cc;}
else return ptr -> second;
}
unsigned size()const{return cc;}
void clear(){cc = 0; pol.clear();}
};
pool<int> M;
int n, col[N];
vector<int> g[N];
inline void addedge(int u, int v){g[u].emplace_back(v);}
inline void ade(int u, int v){addedge(u, v); addedge(v, u);}
int dp[N], secdp[N];
void dfs(int u, int fa)
{
for (int v : g[u])
{
if (v == fa) continue;
dfs(v, u);
if (dp[v] + 1 > dp[u]){secdp[u] = dp[u]; dp[u] = dp[v] + 1;}
else if (dp[v] + 1 > secdp[u]) secdp[u] = dp[v] + 1;
}
}
int main()
{
scanf("%d", &n);
for (int i=1; i<=n; i++) scanf("%d", col+i);
vector<pii> ed;
for (int i=1, u, v; i<n; i++)
{
scanf("%d%d", &u, &v);
if (col[u] == col[v])
{
if (col[u]) B.merge(u, v);
else W.merge(u, v);
}
else ed.emplace_back(make_pair(u, v));
}
for (pii e : ed){int u = e.first, v = e.second; ade(M.get(col[u] ? B.get(u) : W.get(u)), M.get(col[v] ? B.get(v) : W.get(v)));}
dfs(1, 1);
int ans = 0; n = M.size();
for (int i=1; i<=n; i++) chkmax(ans, dp[i] + secdp[i]);
printf("%d\n", (ans + 1) >> 1);
return 0;
}
杂谈
呃呃,这一波反串黑太秀了 /cy
发现 junk 有中国式帆船的意思,?????
附录
承接上次的百合图
以下是博客签名,正文无关
本文来自博客园,作者:yspm,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/16728538.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ