bzoj4543 [POI2014]Hotel加强版 长链剖分+树形DP
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=4543
题解
这道题的弱化版 bzoj3522 [POI2014]Hotel 的做法有好几种吧。
我一开始是另一种做法,所以别人说这个题目可以有长链剖分来加速的时候怎么也想不出来。
枚举 \(i\),令点 \(i\) 为根,统计三个人的中心是 \(i\) 的情况。首先三个人一定在不同的子树中,然后分层统计一下就好了。
还有一个种纯 dp 的做法:
令 \(dp[x][i]\) 表示 \(x\) 的子树中有多少距离 \(x\) 为 \(i\) 的点,\(f[x][i]\) 的子树中有多少点对的 \(lca\)(两个点到 \(lca\) 的距离均为 \(d\))距离 \(x\) 为 \(d-i\)。
这样,合并两个子树的时候考虑先用两个子树 \(dp\) 贡献出 \(f\),然后再各自对各自贡献相加即可。
但是这样做的时间复杂度 \(O(n^2)\)。
因为在这个做法中,第二维只和深度有关,所以考虑长链剖分,把轻儿子合并到重儿子上,因为这样做实际上于长度的值上,每一条长链只会被计算一次,所以时间复杂度为 \(O(n)\)。
具体的实现上可以使用指针移位来实现。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I> inline void read(I &x) {
int dp = 0, c;
while (!isdigit(c = getchar())) c == '-' ? dp = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
dp ? x = -x : 0;
}
const int N = 1e5 + 7;
int n;
ll ans;
int len[N], son[N];
ll a[N << 2], *dp[N], *f[N], *now1, *now2;
struct Edge { int to, ne; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }
inline void dfs1(int x, int fa = 0) {
len[x] = 1;
for fec(i, x, y) if (y != fa) dfs1(y, x), smax(len[x], len[y] + 1) && (son[x] = y);
}
inline void init(int x) {
dp[x] = now1, now1 += len[x];
now2 += len[x], f[x] = now2, now2 += len[x];
assert(now1 - a <= n), assert(now2 - a <= n * 3);
}
inline void dfs2(int x, int fa = 0) {
if (son[fa] != x) init(x);
if (son[x]) dp[son[x]] = dp[x] + 1, f[son[x]] = f[x] - 1, dfs2(son[x], x);
dp[x][0] = 1, ans += f[x][0];
for fec(i, x, y) if (y != fa && y != son[x]) {
dfs2(y, x);
for (int i = 0; i < len[y]; ++i) i && (ans += dp[x][i - 1] * f[y][i]), i + 1 < len[x] && (ans += f[x][i + 1] * dp[y][i]);
for (int i = 0; i < len[y]; ++i) {
if (i + 1 < len[x]) f[x][i + 1] += dp[x][i + 1] * dp[y][i], dp[x][i + 1] += dp[y][i];
if (i) f[x][i - 1] += f[y][i];
}
}
}
inline void work() {
dfs1(1);
now1 = a, now2 = a + n;
dfs2(1);
printf("%lld\n", ans);
}
inline void init() {
read(n);
int x, y;
for (int i = 1; i < n; ++i) read(x), read(y), adde(x, y);
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
bzoj4543 [POI2014]Hotel加强版 长链剖分+树形DP的更多相关文章
- BZOJ4543[POI2014]Hotel加强版——长链剖分+树形DP
题意参见BZOJ3522 n<=100000 数据范围增强了,显然之前的转移方程不行了,那么不妨换一种. 因为不能枚举根来换根DP,那么我们描述的DP方程每个点要计算三个点都在这个点的子树内的方 ...
- BZOJ.4543.[POI2014]Hotel加强版(长链剖分 树形DP)
题目链接 弱化版:https://www.cnblogs.com/SovietPower/p/8663817.html. 令\(f[x][i]\)表示\(x\)的子树中深度为\(i\)的点的个数,\( ...
- 【BZOJ4543】[POI2014]Hotel加强版 长链剖分+DP
[BZOJ4543][POI2014]Hotel加强版 Description 同OJ3522数据范围:n<=100000 Sample Input 7 1 2 5 7 2 5 2 3 5 6 ...
- BZOJ3522&4543 [POI2014]Hotel加强版 长链剖分
上上周见fc爷用长链剖分秒题 于是偷偷学一学 3522的数据范围很小 可以暴力枚举每个点作为根节点来dp 复杂度$O(n^2)$ 考虑令$f[x][j]$表示以$x$为根的子树内距离$x$为$j$的点 ...
- BZOJ4543 POI2014 Hotel加强版 【长链剖分】【DP】*
BZOJ4543 POI2014 Hotel加强版 Description 同OJ3522 数据范围:n<=100000 Sample Input 7 1 2 5 7 2 5 2 3 5 6 4 ...
- 【CF1009F】Dominant Indices(长链剖分优化DP)
点此看题面 大致题意: 设\(d(x,y)\)表示\(x\)子树内到\(x\)距离为\(y\)的点的个数,对于每个\(x\),求满足\(d(x,y)\)最大的最小的\(y\). 暴力\(DP\) 首先 ...
- CF1009F Dominant Indices——长链剖分优化DP
原题链接 \(EDU\)出一道长链剖分优化\(dp\)裸题? 简化版题意 问你每个点的子树中与它距离为多少的点的数量最多,如果有多解,最小化距离 思路 方法1. 用\(dsu\ on\ tree\)做 ...
- 2019.01.08 bzoj4543: [POI2014]Hotel加强版(长链剖分+dp)
传送门 代码: 长链剖分好题. 题意:给你一棵树,问树上选三个互不相同的节点,使得这个三个点两两之间距离相等的方案数. 思路: 先考虑dpdpdp. fi,jf_{i,j}fi,j表示iii子树中离 ...
- BZOJ4543 [POI2014]Hotel加强版
题意 有一个树形结构,每条边的长度相同,任意两个节点可以相互到达.选3个点.两两距离相等.有多少种方案? 数据范围:n<=100000 分析 参照小蒟蒻yyb的博客. 我们先考虑一个\(O(n^ ...
随机推荐
- postgresql获取表最后更新时间(通过表磁盘存储文件时间)
一.创建获取表更新时间的函数 --获取表记录更新时间(通过表磁盘存储文件时间) create or replace function table_file_access_info( IN schema ...
- POJ2395 Out of Hay(求最小生成树中最大的边权,Kruskal)
POJ2395 Out of Hay 寻找最小生成树中最大的边权. 使用 Kruskal 求解,即求选取的第 \(n-1\) 条合法边. 时间复杂度为 \(O(e\log e)\) . #includ ...
- 【洛谷P1036 选数】
这个题显然用到了深搜的内容 让我们跟着代码找思路 #include<bits/stdc++.h>//万能头 ],ans; inline bool prime(int n)//最简单的判定素 ...
- VMware 虚拟化编程(12) — VixDiskLib Sample 程序使用
目录 目录 前文列表 vixDiskLibSample 安装 Sample 程序 Sample 程序使用方法 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/V ...
- loc() iloc() at() iat()函数
1 四个函数都是用于dataframe的定位 []用于直接定位. loc()函数是用真实索引,iloc()函数是用索引序号. loc()函数切片是左闭右闭,iloc()函数切片是左闭右开. at(), ...
- linux下安装python27 nginx 和uwsgi
注意: python27 默认没有安装 pip 和setuptools所以要提前安装.(务必先提前安装python27 哈 ) wget --no-check-certificate https:// ...
- ssm项目的创建思路
·DAO层: 代码:pojo.映射文件.接口文件——Mybatis逆向工程自动生成 配置:ApplicationContext-dao.xml——数据源.连接池.会话工厂.mapper包扫描 ·Ser ...
- ntp局域网时间同步操作
需求:局域网里面有两台电脑需要同步时间 一台windows,一台Linux.把windows当作服务器 windows10自带ntp服务器,可以按如下步骤进行设置 1. 打开注册表编辑器,在运行里面输 ...
- New start-开始我的学习记录吧
不知道从何说起,就从眼下的感想开始吧. 转行是一件不容易的事情! 今天是来北京学习Java的第41天.小测验了两次,一次51分,一次54分. 下午有学长过来分享了他的成长经历,感触很多.不是灌鸡汤,也 ...
- [BNDSOJ] #1106代码
#include<bits/stdc++.h> using namespace std; ]; ][]; int n; bool check(int i,int j) { ]==]==]= ...