题意:给你一颗树,你可以在树上添加一条边,问添加一条边之后的简单路径最多有多少条?简单路径是指路径中的点只没有重复。

思路:添加一条边之后,树变成了基环树。容易发现,以基环上的点为根的子树的点中的简单路径没有增加。所以,问题相当于转化为找一个基环,使得以基环上的点为根的子树Σ(i从1到n) sz[i]  * (sz[i] - 1) / 2最小。我们把式子转化一下变成求(sz[i]的平方和 - n) / 2。相当于我们需要求sz[i]的平方和。但是,我们并不知道哪个是基环,怎么求sz呢?我们发现一个性质:添加的边连接的两点一定是树中度数为1的点,否则,我们一定可以缩小平方和。所以,根据这个性质,我们可以进行树形dp。设dp[i]为以i为根的子树中,选择从i到子树中的某个叶子节点的路径为基环上的点,可以获得的最小的平方和。dp[i] = min(dp[son] + (sz[i] - sz[son]) ^ 2)。

我们假设选择的基环是u -> lca(u, v) -> v ,假设fu为u到lca(u, v)的路径中lca(u, v)的前面一个节点,fv同理,那么平方和为ans = dp[fu] + dp[fv] + (n - sz[fu] - sz[fv]) ^ 2。所以,我们在深搜的时候,找到所有孩子的dp值和sz,枚举是哪两个孩子来更新平方和,这样最坏情况是O(n ^ 2)的,会超时。发现状态转移方程中有fu和fv的乘积项,我们可以考虑斜率优化。把方程移项: dp[fv] = 2 * (n - sz[fu]) * sz[fv] + (ans - dp[fu] - 2 * n * sz[fu])。那么相当于是以sz[fv]为横坐标,dp[fv]为纵坐标,斜率为2 * (n - sz[fu])的直线,要ans最小,需要截距最小。我们把sz从小到大排序,用单调队列维护一个下凸包,之后在单调队列里二分即可。注意的细节:1,二分之后需要判断合不合法,不能fu和fv相等了。2:斜率优化只考虑的fu和fv不等的情况,我们需要特判一下从最优的叶子结点直接连到当前结点的这种情况。

代码:

#pragma comment(linker, "/stack:200000000")
#include <bits/stdc++.h>
#define LL long long
#define pll pair<LL, LL>
using namespace std;
const int maxn = 500010;
vector<int> G[maxn];
LL sz[maxn], dp[maxn];
pll q[maxn], a[maxn], b[maxn];
int l, r;
LL n, ans;
int tot;
map<pll, int> mp;
void add(int x, int y) {
G[x].push_back(y);
G[y].push_back(x);
}
bool check(pll x, pll y, pll z) {
if((y.second - x.second) * (z.first - y.first) < (y.first - x.first) * (z.second - y.second))
return 1;
else
return 0;
}
int binary_search(pll x, LL k) {
if(l == r) return l;
int L = l, R = r;
while(L < R) {
int mid = (L + R) >> 1;
if((q[mid + 1].second - q[mid].second) <= k * (q[mid + 1].first - q[mid].first)) L = mid + 1;
else R = mid;
}
return L;
}
void dfs(int x, int fa) {
sz[x] = 1;
for (auto y : G[x]) {
if(y == fa) continue;
dfs(y, x);
sz[x] += sz[y];
}
for (auto y : G[x]) {
if(y == fa) continue;
dp[x] = min(dp[x], (sz[x] - sz[y]) * (sz[x] - sz[y]) + dp[y]);
}
tot = 0;
for (auto y : G[x]) {
if(y == fa) continue;
b[++tot] = a[y];
}
sort(b + 1, b + 1 + tot);
mp.clear();
if(tot > 1) {
l = 1, r = 0;
for (int i = 1; i <= tot; i++) {
mp[b[i]]++;
while(l < r && !check(q[r - 1], q[r], b[i])) r--;
q[++r] = b[i];
}
for (int i = 1; i <= tot; i++) {
int pos = binary_search(b[i], 2 * (n - b[i].first));
if(q[pos] == b[i]) {
if(mp[b[i]] > 1) {
ans = min(ans, b[i].second + q[pos].second + (n - b[i].first - q[pos].first) * (n - b[i].first - q[pos].first));
} else {
if(pos < r) ans = min(ans, b[i].second + q[pos + 1].second + (n - b[i].first - q[pos + 1].first) * (n - b[i].first - q[pos + 1].first));
else ans = min(ans, b[i].second + q[pos - 1].second + (n - b[i].first - q[pos - 1].first) * (n - b[i].first - q[pos - 1].first));
}
} else {
ans = min(ans, b[i].second + q[pos].second + (n - b[i].first - q[pos].first) * (n - b[i].first - q[pos].first));
}
}
}
for (int i = 1; i <= tot; i++) {
ans = min(ans, b[i].second + (n - b[i].first) * (n - b[i].first));
}
if(fa != -1 && G[x].size() == 1) dp[x] = sz[x] * sz[x];
a[x] = make_pair(sz[x], dp[x]);
}
int main() {
int x, y;
memset(dp, 0x3f, sizeof(dp));
// freopen("1179Din.txt", "r", stdin);
// freopen("1179D1out.txt", "w", stdout);
scanf("%lld", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
}
ans = 1e18;
dfs(1, -1);
ans = min(ans, dp[1]);
ans -= n;
ans /= 2;
ans = 2ll * n * (n - 1) / 2ll - ans;
printf("%lld\n", ans);
}

  

Codeforces 1179D 树形DP 斜率优化的更多相关文章

  1. P3994 高速公路 树形DP+斜率优化+二分

    $ \color{#0066ff}{ 题目描述 }$ C国拥有一张四通八达的高速公路网树,其中有n个城市,城市之间由一共n-1条高速公路连接.除了首都1号城市,每个城市都有一家本地的客运公司,可以发车 ...

  2. 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)

    有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...

  3. bzoj3672: [Noi2014]购票(树形DP+斜率优化+可持久化凸包)

    这题的加强版,多了一个$l_i$的限制,少了一个$p_i$的单调性,难了好多... 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ $\frac {f(j) ...

  4. 【BZOJ-4518】征途 DP + 斜率优化

    4518: [Sdoi2016]征途 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 230  Solved: 156[Submit][Status][ ...

  5. 【BZOJ-3437】小P的牧场 DP + 斜率优化

    3437: 小P的牧场 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 705  Solved: 404[Submit][Status][Discuss ...

  6. 【BZOJ-1010】玩具装箱toy DP + 斜率优化

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8432  Solved: 3338[Submit][St ...

  7. 【BZOJ】1096: [ZJOI2007]仓库建设(dp+斜率优化)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1096 首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min\{d[j]+cost(j+ ...

  8. BZOJ 1096: [ZJOI2007]仓库建设(DP+斜率优化)

    [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在 ...

  9. 学渣乱搞系列之dp斜率优化

    学渣乱搞系列之dp斜率优化 By 狂徒归来 貌似dp的斜率优化一直很难搞啊,尤其是像我这种数学很挫的学渣,压根不懂什么凸包,什么上凸下凸的,哎...说多了都是泪,跟wdd讨论了下,得出一些结论.本文很 ...

随机推荐

  1. Retrofit与RXJava整合(转)

    Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API.下面我用对比的方式来介绍 Retrofit 的 RxJava 版 ...

  2. 第三节:MySQL的调控按钮——启动选项和系统变量

    一.命令行上使用启动选项 启动选项的通用格式 --启动选项1[=值1] --启动选项2[=值2] ... --启动选项n[=值n]    禁止TCP/IP链接 略    修改MySQL服务的默认存储引 ...

  3. ARC101E Ribbons on Tree 容斥原理+dp

    题目链接 https://atcoder.jp/contests/arc101/tasks/arc101_c 题解 直接容斥.题目要求每一条边都被覆盖,那么我们就容斥至少有几条边没有被覆盖. 那么没有 ...

  4. vue项目中axios的封装和使用

    一.axios的功能特点 在浏览器中发送 XMLHttpRequests 请求 在 node.js 中发送 http请求 支持 Promise API 拦截请求和响应 转换请求和响应数据 支持多种请求 ...

  5. Shiro安全框架的说明及配置入门

    Shiro是什么? Shiro是一个非常强大的,易于使用的,开源的,权限框架.它包括了权限校验,权限授予,会话管理,安全加密等组件 什么时候使用它呢? 如果你是设计RBAC基础系统,需要编写大量用于权 ...

  6. 4412 最简Linux驱动

    最简Linux驱动 必备的头文件 • Linux头文件位置– 类似#include <linux/module.h>的头文件,它们是在Linux源码目录下的include/linux/mo ...

  7. PWN入门的入门——工具安装

    安装pwntool: 命令行运行: pip install pwntools python import pwn pwn.asm("xor eax,eax") 出现'1\xc0'  ...

  8. A Guide To using IMU (Accelerometer and Gyroscope Devices) in Embedded Applications.

    介绍 本指南的目的是大家感兴趣的惯性MEMS(微机电系统)传感器,特别是加速计和陀螺仪和IMU组合设备(惯性测量单元). 例如IMU单位:Acc_Gyro_6DOF对MCU处理单元UsbThumb提供 ...

  9. 使用Excel表格的记录单功能轻松处理工作表中数据的方法

    使用Excel表格的记录单功能轻松处理工作表中数据的方法 记录单是将一条记录分别存储在同一行的几个单元格中,在同一列中分别存储所有记录的相似信息段.使用记录单功能可以轻松地对工作表中的数据进行查看.查 ...

  10. CF561做题

    C题: 一期思路:我们发现如果x,y满足条件,那么{x,-y} {-x,y} {-x,-y}也满足条件.那么我们可以只讨论|x| |y|是否满足条件,如果满足条件,那么对ans的贡献是|x|出现次数* ...