Solution -「CF 855G」Harry Vs Voldemort
Link.
给定一棵 个点的树和 次加边操作。求出每次操作后,满足 互不相等,路径 与 无重复边的有序三元组 的个数。
。
考虑原树上,以某个点为 的贡献。记 为 的贡献,则有:
又发现一个边双中的每个点都应是等价的。所以对于以 为顶点的边双,维护 和大小 ,我们也能求出它的贡献:
加边时,暴力爬树,并用并查集维护连通边双即可。
复杂度 (并查集不带启发式合并)。
#include <cstdio>
#include <assert.h>
typedef long long LL;
const int MAXN = 1e5;
int n, ecnt, head[MAXN + 5];
int fa[MAXN + 5], dep[MAXN + 5], siz[MAXN + 5], blk[MAXN + 5];
LL ans, val[MAXN + 5];
struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
inline void link ( const int s, const int t ) {
graph[++ ecnt] = { t, head[s] };
head[s] = ecnt;
}
inline char fgc () {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++;
}
inline int rint () {
int x = 0; char d = fgc ();
for ( ; d < '0' || '9' < d; d = fgc () );
for ( ; '0' <= d && d <= '9'; d = fgc () ) x = x * 10 + ( d ^ '0' );
return x;
}
inline void wint ( const LL x ) {
if ( 9 < x ) wint ( x / 10 );
putchar ( x % 10 ^ '0' );
}
struct DSU {
int fa[MAXN + 5];
inline void init () { for ( int i = 1; i <= n; ++ i ) fa[i] = i; }
inline int find ( const int x ) { return x ^ fa[x] ? fa[x] = find ( fa[x] ) : x; }
inline bool unite ( int x, int y ) {
x = find ( x ), y = find ( y );
return x ^ y ? fa[x] = y, true : false;
}
} dsu;
inline void init ( const int u ) {
siz[u] = blk[u] = 1;
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) ^ fa[u] ) {
dep[v] = dep[fa[v] = u] + 1, init ( v );
siz[u] += siz[v];
val[u] += 1ll * siz[v] * siz[v];
}
}
}
inline void calc ( const int u, const int k ) {
assert ( u == dsu.fa[u] );
int s = blk[u];
ans += 1ll * k * s * ( 1ll * ( n - s ) * ( n - s ) - val[u] - 1ll * ( n - siz[u] ) * ( n - siz[u] ) );
ans += 2ll * k * s * ( s - 1 ) * ( n - s );
ans += 1ll * k * s * ( s - 1 ) * ( s - 2 );
}
inline void merge ( const int u, const int v ) {
assert ( u == dsu.fa[u] && v == dsu.fa[v] && dep[u] < dep[v] );
calc ( u, -1 ), calc ( v, -1 );
val[u] -= 1ll * siz[v] * siz[v], val[u] += val[v], blk[u] += blk[v];
calc ( u, 1 ), dsu.unite ( v, u );
}
int main () {
n = rint (), dsu.init ();
for ( int i = 1, u, v; i < n; ++ i ) {
u = rint (), v = rint ();
link ( u, v ), link ( v, u );
}
init ( 1 );
for ( int i = 1; i <= n; ++ i ) calc ( i, 1 );
wint ( ans ), putchar ( '\n' );
for ( int q = rint (), u, v; q --; ) {
u = rint (), v = rint ();
while ( dsu.find ( u ) ^ dsu.find ( v ) ) {
if ( dep[dsu.find ( u )] < dep[dsu.find ( v )] ) u ^= v ^= u ^= v;
u = dsu.find ( u );
merge ( dsu.find ( fa[u] ), u );
}
wint ( ans ), putchar ( '\n' );
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现