看了题目的讨论才会做的

首先一点,算每条边(u, v)对于n*(n+1)/2种[l, r]组合的贡献

正着算不如反着算

哪些[l, r]的组合没有包含这条边(u, v)呢

这个很好算

只需要统计u这半边的点中有哪些连续数字,连续的数字就是一个[l, r]组合

就可以算出u这半边有哪些潜在的[l, r]组合

当然u这半边算好了,v这半边正好是u的数字反过来

这个过程可以使用set来统计,很好写

现在我们解决了对于一个边怎么算贡献

现在需要使用点分治

使用点分治求重心进行遍历保证了每个点至多被放入set log(n)次

所以复杂度大约nlog(n)

  1. #include <algorithm>
  2. #include <cmath>
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <iostream>
  6. #include <map>
  7. #include <queue>
  8. #include <set>
  9. #include <stack>
  10. #include <vector>
  11. using namespace std;
  12. typedef long long ll;
  13. const int N = 1e5 + 5;
  14. #define MS(x, y) memset(x, y, sizeof(x))
  15. #define MP(x, y) make_pair(x, y)
  16. const int INF = 0x3f3f3f3f;
  17. int n;
  18. struct GraphUnit {
  19. int to, next;
  20. } Tree[N << 1];
  21. int head[N], tot;
  22. bool vis[N];
  23. void addEdge(int from, int to) {
  24. Tree[tot].to = to;
  25. Tree[tot].next = head[from];
  26. head[from] = tot++;
  27. }
  28. set<int> vertexSet;
  29. int min_MaxSon_Centrol_Num;
  30. int min_MaxSon_Centrol_Pos;
  31. ll ans = 0;
  32. int getCentrol(int vertex, int preVertex) {
  33. int fatherSum = 1;
  34. int maxSon = -1;
  35. vertexSet.insert(vertex);
  36. for (int i = head[vertex]; ~i; i = Tree[i].next) {
  37. int to = Tree[i].to;
  38. if (to == preVertex || vis[to])
  39. continue;
  40. int sonSum = getCentrol(to, vertex);
  41. maxSon = max(maxSon, sonSum);
  42. fatherSum += sonSum;
  43. }
  44. maxSon = max(maxSon, n - fatherSum);
  45. if (maxSon < min_MaxSon_Centrol_Num) {
  46. min_MaxSon_Centrol_Num = maxSon;
  47. min_MaxSon_Centrol_Pos = vertex;
  48. }
  49. return fatherSum;
  50. }
  51. ll Cal(int x) {
  52. return 1ll * x * (x + 1) / 2;
  53. }
  54. void solveTheSet() {
  55. int pre = 0;
  56. int cnt = 0;
  57. ll preans = ans;
  58. for (auto it = vertexSet.begin(); it != vertexSet.end(); ++it) {
  59. int number = *it;
  60. if (number == pre + 1)
  61. cnt++;
  62. else {
  63. ans += Cal(cnt);
  64. ans += Cal(number - pre - 1);
  65. cnt = 1;
  66. }
  67. pre = number;
  68. }
  69. ans += Cal(cnt);
  70. ans += Cal(n - pre);
  71. // printf("hh :%lld\n", ans - preans);
  72. }
  73. void divideAndConquer(int vertex, int preVertex) {
  74. min_MaxSon_Centrol_Num = INF;
  75. vertexSet.clear();
  76. getCentrol(vertex, vertex);
  77. int root = min_MaxSon_Centrol_Pos;
  78. // printf("%d\n", root);
  79. vis[root] = true;
  80. if (vertex != preVertex) { // only the first we don't need to solve, because it don't have the pre edge
  81. solveTheSet();
  82. }
  83. for (int i = head[root]; ~i; i = Tree[i].next) {
  84. int to = Tree[i].to;
  85. if (vis[to])
  86. continue;
  87. divideAndConquer(to, root);
  88. }
  89. }
  90. int main() {
  91. while (~scanf("%d", &n)) {
  92. memset(vis, 0, sizeof(vis));
  93. memset(head, -1, sizeof(head));
  94. tot = 0;
  95. ans = 0;
  96. for (int i = 1; i < n; ++i) {
  97. int from, to;
  98. scanf("%d %d", &from, &to);
  99. addEdge(from, to);
  100. addEdge(to, from);
  101. }
  102. divideAndConquer(1, 1);
  103. printf("%lld\n", Cal(n) * (n - 1) - ans);
  104. }
  105. return 0;
  106. }

hihocoder [Offer收割]编程练习赛52 D 部门聚会的更多相关文章

  1. hihocoder [Offer收割]编程练习赛4

    描述 最近天气炎热,小Ho天天宅在家里叫外卖.他常吃的一家餐馆一共有N道菜品,价格分别是A1, A2, ... AN元.并且如果消费总计满X元,还能享受优惠.小Ho是一个不薅羊毛不舒服斯基的人,他希望 ...

  2. hihocoder [Offer收割]编程练习赛61

    [Offer收割]编程练习赛61 A:最小排列 给定一个长度为m的序列b[1..m],再给定一个n,求一个字典序最小的1~n的排列A,使得b是A的子序列. 贪心即可,b是A的子序列,把不在b中的元素, ...

  3. ACM学习历程—Hihocoder [Offer收割]编程练习赛1

    比赛链接:http://hihocoder.com/contest/hihointerview3/problem/1 大概有一个月没怎么打算法了.这一场的前一场BC,也打的不是很好.本来Div1的A和 ...

  4. hihocoder offer收割编程练习赛8 C 数组分拆

    思路:(引自bfsoyc的回答:http://hihocoder.com/discuss/question/4160) 动态规划.状态dp[i]表示 前i个数的合法的方案数,转移是 dp[i] = s ...

  5. hihocoder [Offer收割]编程练习赛18 C 最美和弦(dp)

    题目链接:http://hihocoder.com/problemset/problem/1532 题解:一道基础的dp,设dp[i][j][k][l]表示处理到第几个数,当前是哪个和弦错了几次初始x ...

  6. hihoCoder [Offer收割]编程练习赛3 D子矩阵求和

    子矩阵求和 http://hihocoder.com/discuss/question/3005 声明一下: n是和x一起的,m是和y一起的 x是横着的,y是纵着的,x往右为正,y往下为正 (非常反常 ...

  7. hihocoder [Offer收割]编程练习赛14

    A.小Hi和小Ho的礼物 谜之第1题,明明是第1题AC率比C还要低.题目是求在n个不同重量袋子选4袋,2袋给A,2袋给B,使2人获得重量相同,求问方案数. 我也是一脸懵b...o(n2)暴力枚举发现把 ...

  8. hihocoder [Offer收割]编程练习赛8

    第一次做这种比赛,被自己坑的好惨... A.这道题的关键其实是如果有k和n满足kD+F>nL>kD则不能走无限远,分支看似难整理,其实比较简单,F>L根本就不用算了,明摆着就是Bsi ...

  9. hihocoder [Offer收割]编程练习赛12 [1495] ---- 矩形分割

    原题链接 矩形分割 算法分析: 解决该题要用到"并查集"的思想. 这里有一篇不错的博客介绍并查集: 并查集(Union-Find)算法介绍 记 int total=N*M,这里会有 ...

随机推荐

  1. Java中字符串的一些常见方法

    1.Java中字符串的一些常见方法 /** * */ package com.you.model; /** * @author Administrator * @date 2014-02-24 */ ...

  2. VxWorks 操作系统内存布局

    在VxWorks操作系统过程中可能使用到的BootRom和VxWorks内核映像本身都可以存在两种方式:压缩的和非压缩的. 1.非压缩形式 如果没有进行压缩,则只有一次重定位,即从ROM到RAM只存在 ...

  3. 错误代码: 1449 The user specified as a definer ('root'@'%') does not exist

    1. 错误描述 1 queries executed, 0 success, 1 errors, 0 warnings 查询:call analyse_use('20150501','20150601 ...

  4. zTree实现更新根节点中第i个节点的名称

    zTree实现更新根节点中第i个节点的名称 1.实现源码 <!DOCTYPE html> <html> <head> <title>zTree实现基本树 ...

  5. freemarker写select组件报错总结(四)

    1.错误描述 <html> <head> <meta http-equiv="content-type" content="text/htm ...

  6. 芝麻HTTP:爬虫之设置Selenium+Chrome代理

    微博登录限制了错误次数···加上Cookie大批账号被封需要从Cookie池中 剔除被封的账号··· 需要使用代理··· 无赖百度了大半天都是特么的啥玩意儿???结果换成了 Google手到擒来 分分 ...

  7. js数组使用JSON.stringify()和toString()的区别,JSON.parse

    JSON.stringify()中的<br><br>var arr = [1,2,3,4]; console.log(arr.toString()); // 1,2,3,4 a ...

  8. 通过回调函数的理解来进一步理解ajax及其注意的用法

    一,再一次理解回调函数 (function($){ $.fn.shadow = function(opts){ //定义的默认的参数 var defaults = { copies: 5, opaci ...

  9. GAN 转

    生成式对抗网络(GAN)是近年来大热的深度学习模型.最近正好有空看了这方面的一些论文,跑了一个GAN的代码,于是写了这篇文章来介绍一下GAN. 本文主要分为三个部分: 介绍原始的GAN的原理 同样非常 ...

  10. 微信小程序hidden

    首先hidden默认在display:block;情况下是会默认生效的: but在很多时候只在初始值下有效, 在data下声明 flag:true; 方法中: 无效,所以尽量不要使用hidden这个属 ...