看了题目的讨论才会做的

首先一点,算每条边(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. vxWorks/BootROM Imageq启动顺序详解

    vxWorks/BootROM Imageq启动顺序详解 VxWorks image     分为在ROM中运行和在RAM中运行两种,两者启动顺序的区别在于sysInit()函数的调用,该函数在RAM ...

  2. HighCharts之2D条状图

    HighCharts之2D条状图 1.HighCharts之2D条状图源码 bar.html: <!DOCTYPE html> <html> <head> < ...

  3. C#中各种计时器 Stopwatch、TimeSpan

    1.使用 Stopwatch 类 (System.Diagnostics.Stopwatch)Stopwatch 实例可以测量一个时间间隔的运行时间,也可以测量多个时间间隔的总运行时间.在典型的 St ...

  4. JavaScript解决select下拉框中的内容太长显示不全的问题

    JavaScript解决select下拉框中的内容太长显示不全的问题 1.说明 有些情况下,select下拉框的内容过长,导致部分看不见: 现在通过鼠标事件,让下拉框中的内容显示完全 2.实现源码 & ...

  5. xml的SAX解析和dom解析的区别

    一,区别 DOM解析 SAX解析 原理: 一次性加载xml文档,不适合大容量的文件读取 原理: 加载一点,读取一点,处理一点.适合大容量文件的读取 DOM解析可以任意进行增删改成 SAX解析只能读取 ...

  6. WPF基础篇之空间布局

    由于之前自己做的都是大多是B/S架构的项目,加入新公司,公司现在用的WPF,在WPF中一个比较重要的知识点:布局 在网上找到一篇比较好的介绍WPF布局的文章. 文章地址:http://www.cnbl ...

  7. 浏览器全屏之requestFullScreen全屏与F11全屏

    一.简介 浏览器全屏有两种方式,一种是HTML5新增的requestFullscree全屏,另一种是摁F11实现的全屏,本文将详解两种全屏的特点以及实现代码. 二.requestFullscreen全 ...

  8. Redis总结(七)Redis运维常用命令

    redis 服务器端命令 redis 127.0.0.1:6380> time  ,显示服务器时间 , 时间戳(秒), 微秒数 1) "1375270361" 2) &quo ...

  9. 【BZOJ2440】完全平方数(二分答案,莫比乌斯反演)

    [BZOJ2440]完全平方数(二分答案,莫比乌斯反演) 题面 BZOJ 题解 很显然,二分一个答案 考虑如何求小于等于这个数的非完全平方数倍数的个数 这个明显可以直接,莫比乌斯反演一下 然后这题就很 ...

  10. 谷歌chrome 插件(扩展)开发——基础篇

    公司需要开发chrome浏览器右键菜单功能,点击后可传页面的相关参数与客户端(winform)交互. 我对chrome扩展一无所知,所以第一阶段,我称之为"扫盲".也就是先找些相关 ...