看了题目的讨论才会做的

首先一点,算每条边(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)

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
#define MS(x, y) memset(x, y, sizeof(x))
#define MP(x, y) make_pair(x, y)
const int INF = 0x3f3f3f3f; int n;
struct GraphUnit {
int to, next;
} Tree[N << 1];
int head[N], tot;
bool vis[N];
void addEdge(int from, int to) {
Tree[tot].to = to;
Tree[tot].next = head[from];
head[from] = tot++;
}
set<int> vertexSet;
int min_MaxSon_Centrol_Num;
int min_MaxSon_Centrol_Pos;
ll ans = 0;
int getCentrol(int vertex, int preVertex) {
int fatherSum = 1;
int maxSon = -1;
vertexSet.insert(vertex);
for (int i = head[vertex]; ~i; i = Tree[i].next) {
int to = Tree[i].to;
if (to == preVertex || vis[to])
continue;
int sonSum = getCentrol(to, vertex);
maxSon = max(maxSon, sonSum);
fatherSum += sonSum;
}
maxSon = max(maxSon, n - fatherSum);
if (maxSon < min_MaxSon_Centrol_Num) {
min_MaxSon_Centrol_Num = maxSon;
min_MaxSon_Centrol_Pos = vertex;
}
return fatherSum;
}
ll Cal(int x) {
return 1ll * x * (x + 1) / 2;
}
void solveTheSet() {
int pre = 0;
int cnt = 0;
ll preans = ans;
for (auto it = vertexSet.begin(); it != vertexSet.end(); ++it) {
int number = *it;
if (number == pre + 1)
cnt++;
else {
ans += Cal(cnt);
ans += Cal(number - pre - 1);
cnt = 1;
}
pre = number;
}
ans += Cal(cnt);
ans += Cal(n - pre);
// printf("hh :%lld\n", ans - preans);
}
void divideAndConquer(int vertex, int preVertex) {
min_MaxSon_Centrol_Num = INF;
vertexSet.clear();
getCentrol(vertex, vertex);
int root = min_MaxSon_Centrol_Pos;
// printf("%d\n", root);
vis[root] = true;
if (vertex != preVertex) { // only the first we don't need to solve, because it don't have the pre edge
solveTheSet();
}
for (int i = head[root]; ~i; i = Tree[i].next) {
int to = Tree[i].to;
if (vis[to])
continue;
divideAndConquer(to, root);
}
}
int main() {
while (~scanf("%d", &n)) {
memset(vis, 0, sizeof(vis));
memset(head, -1, sizeof(head));
tot = 0;
ans = 0;
for (int i = 1; i < n; ++i) {
int from, to;
scanf("%d %d", &from, &to);
addEdge(from, to);
addEdge(to, from);
} divideAndConquer(1, 1); printf("%lld\n", Cal(n) * (n - 1) - ans);
}
return 0;
}

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. Jquery常用操作:checkbox、select取值,radio、checkbox、select选中及其相关

    常用Jquery操作:checkbox取值.select取值.radio选中.checkbox选中.select选中及其相关: 1.影藏页面元素 使用jquery真的很方便,比如要控制div的显示与隐 ...

  2. VxWorks 符号表

    符号表初始化           符号表用于建立符号名称.类型和值之间的关系.其中,名称为null结尾的任意字符串:类型为标识各种符号的整数:值为一个字符指针.符号表主要用来作为目标模块加载的基础,但 ...

  3. 序列化Json格式

    Json = JsonUtil.Serialize(new { code = 1, msg = "文件删除成功" }); public class JsonUtil     {   ...

  4. Django学习-16-Session

    1.保存在服务器的键值对           2.Session做验证时,还要依赖Cookie(重要).当用户登录成功时,生成随机字符串,一份放到Session,一份放到Cookie.当用户再次登录, ...

  5. 常用UI框架

    jQuery Smart UI 链接地址:http://smartui.chinamzz.com Liger UI框架链接地址:http://www.ligerui.com/ DWZ富客户端框架(jQ ...

  6. 对于多线程下Servlet以及Session的一些理解

    今天,小伙伴突然问到了Servlet是不是线程安全的问题.脑子当时一卡壳,只想到了单实例多线程.这里做一些总结. Servlet体系是建立在Java多线程的基础之上的,它的生命周期是由Tomcat来维 ...

  7. 【POJ2387】Til the Cows Come Home (最短路)

    题面 Bessie is out in the field and wants to get back to the barn to get as much sleep as possible bef ...

  8. Python中的栈溢出及解决办法

    1.递归函数 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. 举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示, ...

  9. 与二叉树有关的编程题的Java代码实现

    该文章几乎包含了所有与二叉树相关的基础面试题,其中包括二叉树的四种遍历方法:前序遍历,中序遍历,后续遍历,层次遍历. 算法题包括: 二叉树的序列化和反序列化 给定一颗二叉搜索树,请找出其中的第k大的结 ...

  10. asp.net core 四 IOC&DI Autofac

    其实关于IOC,DI已经有了很多的文章,但是自己在使用中还是有很多困惑,而且相信自己使用下,印象还是会比较深刻的 关于这段时间一直在学习.net core,但是这篇文章是比较重要的,也是我自己觉得学习 ...