【题解】 P5904 [POI2014]HOT-Hotels 加强版
题意
给定一棵树,求树上存在多少个三元组
分析
发现答案无非就是下面两种。
对于左边的情况,我们显然可以用
那么就先考虑右边的情况,考虑用
那么右边的情况就可以看成:
这样的话,只需保证左边的节点和右边两个节点不在某一个点的同一个儿子的子树内,那么就不会被重复统计。
还有一种情况有一个点是
那么,节点
接下来考虑如何转移
考虑
对于左边的情况,发现
而右边的情况,发现
这样我们就得到了一个在使用前缀和的前提下
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 1e5 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } int n, ans; int tot, Head[N], to[N << 1], Next[N << 1]; int mxd[N], son[N], *f[N], *g[N], suf[N << 2], *cur = suf; void add(int u, int v){ to[++tot] = v, Next[tot] = Head[u], Head[u] = tot; } void dfs1(int x, int fa){ for(int i = Head[x]; i; i = Next[i]){ int y = to[i]; if(y == fa) continue; dfs1(y, x); if(mxd[y] > mxd[son[x]]) son[x] = y; } mxd[x] = mxd[son[x]] + 1; } void dfs2(int x, int fa){ if(son[x]) f[son[x]] = f[x] + 1, g[son[x]] = g[x] - 1, dfs2(son[x], x); f[x][0] = 1, ans += g[x][0]; for(int i = Head[x]; i; i = Next[i]){ int y = to[i]; if(y == fa || y == son[x]) continue; f[y] = cur, cur += mxd[y] << 1, g[y] = cur, cur += mxd[y] << 1; dfs2(y, x); //f[x], g[x] 表示是之前子树节点 f 的总和 for(int j = 0; j < mxd[y]; ++j){ if(j) ans += f[x][j - 1] * g[y][j]; ans += g[x][j + 1] * f[y][j]; } for(int j = 0; j < mxd[y]; ++j){ g[x][j + 1] += f[x][j + 1] * f[y][j]; if(j) g[x][j - 1] += g[y][j]; //前缀和 f[x][j + 1] += f[y][j]; } } } signed main(){ n = read(); for(int i = 1; i < n; ++i){ int u = read(), v = read(); add(u, v), add(v, u); } dfs1(1, 0), f[1] = cur, cur += mxd[1] << 1, g[1] = cur, cur += mxd[1] << 1; dfs2(1, 0); printf("%lld\n", ans); return 0; }
本文作者:南风未起
本文链接:https://www.cnblogs.com/jiangchen4122/p/17434946.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步