CF1179D Fedor Runs for President


题意

  • 给一棵n个点的树,求加入一条边后,最多有多少条无向简单路径

  • 简单路径定义为任意一个点最多经过一次的路径


思路

  • 我们若将ij相连,我们可以将ij的路径拉直

    • 路径上每个点有一个以该点为根的子树,记子树大小为size[i]
    • 该路径上不同子树之间的点相互访问的简单路径增加了一条
    • 增加路径数 ∑ ( n − s i z e [ i ] ) ∗ s i z e [ i ] = 1 2 ( n 2 − ∑ s i z e [ i ] 2 ) \sum {(n-size[i])*size[i]} = \frac{1}{2} (n^2- \sum size[i]^2) ∑(n−size[i])∗size[i]=21​(n2−∑size[i]2),i为路径上的点
    • 综上,我们要求的就是 ∑ s i z e [ i ] \sum size[i] ∑size[i]的最小值
  • 然后我们发现一个规律:路径的两端必定为叶子或者根
    • 若不为叶子,我可以让他的端点向子树方向扩展,那么得到size[i]更小( n 2 > x 2 + ( n − x ) 2 n^2>x^2+(n-x)^2 n2>x2+(n−x)2)
  • dp[i]为以i为根的子树中 ∑ s i z e [ i ] \sum size[i] ∑size[i]最小的链
    • 转移方程为 d p [ i ] = m i n ( d p [ j ] + ( s i z e [ i ] − s i z e [ j ] ) 2 ) dp[i]=min(dp[j]+(size[i]-size[j])^2) dp[i]=min(dp[j]+(size[i]−size[j])2)
n_size[now] = 1;
for (auto it : E[now])
{if (it == fa)continue;dfs(it, now);n_size[now] += n_size[it];
}
dp[now] = n_size[now] * n_size[now];
for (auto it : E[now])
{if (it == fa)continue;dp[now] = min(dp[now], dp[it] + (n_size[now] - n_size[it]) * (n_size[now] - n_size[it]));
}
  • 对于根s,可以将ij和并

    • a n s = m i n ( a n s , d p [ i ] + d p [ j ] + ( n − s i z e [ i ] − s i z e [ j ] ) 2 ) ans=min(ans,dp[i]+dp[j]+(n-size[i]-size[j])^2) ans=min(ans,dp[i]+dp[j]+(n−size[i]−size[j])2)
    • 可以将si合并, a n s = m i n ( d p [ i ] + ( n − s i z e [ i ] ) 2 ) ans=min(dp[i]+(n-size[i])^2) ans=min(dp[i]+(n−size[i])2)
  • 对上面 n 2 n^2 n2做法显然会t,我们尝试斜率优化
    • a n s = d p [ i ] + d p [ j ] + ( n − s i z e [ i ] − s i z e [ j ] ) 2 ans = dp[i] + dp[j] + (n - size[i] - size[j]) ^ 2 ans=dp[i]+dp[j]+(n−size[i]−size[j])2
    • d p [ j ] + ( n − s i z e [ j ] ) 2 = 2 ∗ s i z e [ i ] ∗ ( n − s i z e [ j ] ) + a n s − s i z e [ i ] 2 − d p [ i ] dp[j] + (n - size[j]) ^ 2 = 2 * size[i] * (n - size[j]) + ans - size[i] ^ 2 - dp[i] dp[j]+(n−size[j])2=2∗size[i]∗(n−size[j])+ans−size[i]2−dp[i]
    • x: n-size[j]
    • y : d p [ j ] + ( n − s i z e [ j ] ) 2 y: dp[j] +(n-size[j])^2 y:dp[j]+(n−size[j])2
    • k: 2*size[i]
    • b : a n s − s i z e [ i ] 2 − d p [ i ] b: ans- size[i] ^2 - dp[i] b:ans−size[i]2−dp[i]
register LL x, y, k, b;
q[top = 1] = make_pair(n - s[1].first, s[1].second + (n - s[1].first) * (n - s[1].first));
for (int i = 2; i <= tot; i++)
{x = n - s[i].first;y = s[i].second + x * x;k = 2 * s[i].first;int pos = binary_search(k);b = q[pos].second - k * q[pos].first;ans = min(ans, b + s[i].first * s[i].first + s[i].second);//(y2-y1)/(x2-x1) >= (y3-y1)/(x3-x1)while (top > 1 && (q[top].second - q[top - 1].second) * (x - q[top - 1].first) >= (y - q[top - 1].second) * (q[top].first - q[top - 1].first))top--;q[++top] = make_pair(x, y);
}
ans = min(ans, dp[now] + (n - n_size[now]) * (n - n_size[now]));
a[now] = make_pair(n_size[now], dp[now]);

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
typedef long long LL;
LL n;
vector<int> E[maxn];
LL n_size[maxn], dp[maxn];
//dp表示以 i 为根的子数,连接叶子节点 子树平方和最小的路径
typedef pair<LL, LL> pll;
bool cmp(pll& a, pll& b)
{return a.first > b.first;
}
pll a[maxn], s[maxn], q[maxn];
int top;
LL binary_search(LL k)
{if (top == 1)return 1;int l = 2, r = top, mid, ans = 1;while (l <= r) {mid = (l + r) >> 1;if ((q[mid].second - q[mid - 1].second) <= k * (q[mid].first - q[mid - 1].first))ans = max(ans, mid),l = mid + 1;elser = mid - 1;}return ans;
}
LL ans = 1e18;
void dfs(int now, int fa)
{n_size[now] = 1;for (auto it : E[now]) {if (it == fa)continue;dfs(it, now);n_size[now] += n_size[it];}dp[now] = n_size[now] * n_size[now];for (auto it : E[now]) {if (it == fa)continue;dp[now] = min(dp[now], dp[it] + (n_size[now] - n_size[it]) * (n_size[now] - n_size[it]));}// ans = dp[i] + dp[j] + (n - size[i] - size[j]) ^ 2// dp[j] + (n - size[j]) ^ 2 = 2 * size[i] * (n - size[j]) + ans - size[i] ^ 2 - dp[i]int tot = 0;for (auto it : E[now]) {if (it == fa)continue;s[++tot] = a[it];}// x: n-size[j]// y: dp[j] +(n-size[j])^2// k: 2*size[i]// b: ans- size[i] ^2 - dp[i]sort(s + 1, s + 1 + tot, cmp);int l = 1, r = 1;register LL x, y, k, b;q[top = 1] = make_pair(n - s[1].first, s[1].second + (n - s[1].first) * (n - s[1].first));for (int i = 2; i <= tot; i++) {x = n - s[i].first;y = s[i].second + x * x;k = 2 * s[i].first;int pos = binary_search(k);b = q[pos].second - k * q[pos].first;ans = min(ans, b + s[i].first * s[i].first + s[i].second);//(y2-y1)/(x2-x1) >= (y3-y1)/(x3-x1)while (top > 1 && (q[top].second - q[top - 1].second) * (x - q[top - 1].first) >= (y - q[top - 1].second) * (q[top].first - q[top - 1].first))top--;q[++top] = make_pair(x, y);}ans = min(ans, dp[now] + (n - n_size[now]) * (n - n_size[now]));a[now] = make_pair(n_size[now], dp[now]);
}
int main()
{// freopen("out.txt", "r", stdin);scanf("%I64d", &n);int u, v;for (int i = 1; i < n; i++) {scanf("%d%d", &u, &v);E[u].push_back(v);E[v].push_back(u);}dfs(1, 0);//cout << ans << '\n';printf("%I64d\n", n * (n - 1) / 2 + (n * n - ans) / 2);return 0;
}

CF1179D Fedor Runs for President相关推荐

  1. Codeforces 1179 D - Fedor Runs for President

    D - Fedor Runs for President 思路: 推出斜率优化公式后,会发现最优点只可能来自凸斜率中的第一个元素和最后一个元素, 这两个元素不用维护凸斜率也能知道,就是第一个和上一个元 ...

  2. Codeforces 1179D Fedor Runs for President [DP,斜率优化]

    Codeforces 思路 考虑把连的那两个点中间的链提出来,那么就会变成一条链,链上的每个点挂着一棵子树的形式. 设那些子树的大小为\(S_1,S2,\cdots\),那么新加的简单路径个数就是 \ ...

  3. CF-567F(President and Roads) DAG必经边

    CF-567F(President and Roads) 题目链接 题意 S−>ES->ES−>E的DAGDAGDAG中求: DAGDAGDAG中必经边输出"YESYESY ...

  4. 2019.11.2图论专题(AtCoder Splatter Painting、President and Roads、Shortest Cycle、ISlands II)

    D:AtCoder Grand Contest 012 Splatter Painting 题目描述 Squid喜欢在图中为一些顶点染色(毕竟是鱿鱼 ) 现在有一张由 N 个顶点和 M 条边组成的简单 ...

  5. How Apache Zeppelin runs a paragraph

    转发一篇zeppelin的主力committer Jongyoul Lee的讲解zeppelin的paragraph的运行机制的文章,原文地址:https://medium.com/apache-ze ...

  6. vivado [Runs 36-335] DCP is not a valid design checkpoint问题解决方法

    (1)问题描述 有时候vivado会莫名的出现一下错误: [Runs 36-335] 'xxx.dcp' is not a valid design checkpoint 在遇到这个错误的时候大家不要 ...

  7. 20100304-001-美国总统The President of the United States of America

    美国总统(The President of the United States of America) 美国宪法 1789年4月30日,乔治·华盛顿 1793年3月4日,乔治·华盛顿 1797年3月4 ...

  8. Vivado报错:[Runs 36-527] DCP does not exist

    Vivado报错:[Runs 36-527]  DCP does not exist 问题描述:综合工程时,某个IP文件被标红,出现[Runs 36-527]  DCP does not exist. ...

  9. 转载 GIS的下个十年(Peter Batty, president, Spatial Networking)

    GIS的下个十年(Peter Batty, president, Spatial Networking) 2008年12月14日 星期日 20:16 转载自:http://hi.baidu.com/l ...

最新文章

  1. Apache 反向代理,Laravel获取用户真实IP
  2. 我眼中的计算机,我眼中的计算机-计算机开机背后的故事
  3. 文献学习(part78-B)--A Survey of Clustering Algorithms for Big Data: T axonomy Empirical Analysis
  4. HDU2546_用01背包做
  5. 理解SQL【转http://blog.jobbole.com/55086/】
  6. WiFi(网络)调试Android手机
  7. 日志时间与系统时间不一致问题解决方法
  8. git个人常用的命令
  9. 2013Esri全球用户大会QA之ArcGIS未来发展
  10. 【深度相机系列二】深度相机原理揭秘--飞行时间(TOF)
  11. Springer-Verlag免费下载图书400本
  12. 公众号第三方平台开发 教程一 创建公众号第三方平台
  13. C#-进击Hangfire
  14. WIN 7系统建立无线热点
  15. .Net Core 3.0 控制台 WebAPI 开发 基础环境搭建.
  16. 五大列级庄_详解五大名庄背后的1855分级
  17. python中文版下载安装教程,python最新版本安装教程
  18. 编程之类的文案_有哪些让人眼前一亮的广告文案?
  19. cad在线转换_CAD批量转PDF?分享两种方法,一分钟完成所有图纸转换!
  20. 宁波远洋上交所上市:市值155亿 上半年营收23亿净利4亿

热门文章

  1. 在html中使用fontIcon 的图标
  2. 这才是互联网赚钱的正确姿势!你学会了吗?
  3. 免杀方法(三)msf加载器免杀
  4. 江苏二本计算机科学与技术好的学校排名,江苏最好的二本学校,2021年江苏二本学校排名前十名单公布...
  5. gm怎么刷东西 rust_决战常用GM刷物品命令
  6. HTML的body元素
  7. 安装 SASS 失败,提示‘mkmf.rb can't find header files for ruby at /usr/share/include/ruby.h’
  8. checkbox的点击事件
  9. 英语流利说 第31天
  10. office中word使用过程中字体排版