clj在某场hihoCoder比赛中的一道题,表示clj的数学题实在6,这道图论貌似还算可以。。。

题目链接:http://hihocoder.com/problemset/problem/1167

由于是中文题目,题意不再赘述。

对于任意两条小精灵的活动路径a和b,二者相交的判断条件为b的两个端点的LCA在a的路径上;那么我们可以首先将每个活动路径端点的LCA离线预处理出来,对每个节点LCA值+1。

然后以某个节点(我选择的是节点1)为根进行深搜,算出一条从节点1到节点x的LCA值和,那么任意路径a(假设其两端点分别是A和B)上的节点个数就是sum[A] + sum[B] - 2 * sum[LCA(A,B)]。

最后,对于某些点,如果它是不止一条路径的LCA,那么我们只需要对最终答案乘以C(LCAnum, 2)的组合数就好。

【PS:clj给出的题解中,采用了点分治+LCA的方式,虽然看懂了题意,但是表示对递归分治之后的路径,如何求出其上的LCAnum,并没有多好的想法,还望巨巨能指点一下,Thx~】

 #include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
#define MAXN 100010
struct Edge {
int to, next;
} edge[MAXN << ];
struct Node {
int to, next, num;
} Query[MAXN << ];
struct node {
int u, v, lca;
} input[MAXN];
int totEdge, totQuery, n, m;
int headEdge[MAXN], headQuery[MAXN];
int ancestor[MAXN], father[MAXN], LCAnum[MAXN], sum[MAXN];
bool vis[MAXN];
void addEdge(int from, int to) {
edge[totEdge].to = to;
edge[totEdge].next = headEdge[from];
headEdge[from] = totEdge++;
}
void addQuery(int from, int to, int x) {
Query[totQuery].to = to;
Query[totQuery].num = x;
Query[totQuery].next = headQuery[from];
headQuery[from] = totQuery++;
}
void init() {
memset(headEdge, -, sizeof(headEdge));
memset(headQuery, -, sizeof(headQuery));
memset(father, -, sizeof(father));
memset(vis, false, sizeof(vis));
memset(sum, , sizeof(sum));
memset(LCAnum, , sizeof(LCAnum));
totEdge = totQuery = ;
}
int find_set(int x) {
if(x == father[x]) return x;
else return father[x] = find_set(father[x]);
}
void union_set(int x, int y) {
x = find_set(x); y = find_set(y);
if(x != y) father[y] = x;
}
void Tarjan(int u) {
father[u] = u;
for(int i = headEdge[u]; i != -; i = edge[i].next) {
int v = edge[i].to;
if(father[v] != -) continue;
Tarjan(v);
union_set(u, v);
}
for(int i = headQuery[u]; i != -; i = Query[i].next) {
int v = Query[i].to;
if(father[v] == -) continue;
input[Query[i].num].lca = find_set(v);
}
}
void DFS(int u, int pre) {
vis[u] = ;
sum[u] = sum[pre] + LCAnum[u];
for(int i = headEdge[u]; i != -; i = edge[i].next) {
int v = edge[i].to;
if(vis[v]) continue;
DFS(v, u);
}
}
int main() {
init();
scanf("%d%d", &n, &m);
for(int i = ; i < n - ; i++) {
int a, b;
scanf("%d%d", &a, &b);
addEdge(a, b); addEdge(b, a);
}
for(int i = ; i < m; i++) {
int a, b;
scanf("%d%d", &a, &b);
input[i].u = a, input[i].v = b;
addQuery(a, b, i); addQuery(b, a, i);
}
Tarjan();
for(int i = ; i < m; i++)
LCAnum[input[i].lca]++;
DFS(, );
LL ans = ;
for(int i = ; i < m; i++) {
ans += (sum[input[i].u] + sum[input[i].v] - * sum[input[i].lca]);
}
for(int i = ; i <= n; i++) {
ans += (LL)LCAnum[i] * (LCAnum[i] - ) / ;
}
printf("%lld\n", ans);
return ;
}

转载:)

hihoCoder挑战赛11.题目4 : 高等理论计算机科学(LCA)的更多相关文章

  1. 【Hihocoder 1167】 高等理论计算机科学 (树链的交,线段树或树状数组维护区间和)

    [题意] 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 少女幽香这几天正在学习高等理论计算机科学,然而她什么也没有学会,非常痛苦.所以她出去晃了一晃,做起了一些没什么意 ...

  2. [题解]hihoCoder挑战赛18——题目1 神奇字符串

    题目地址:http://hihocoder.com/problemset/problem/1264 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 我们说两个字符串是非常 ...

  3. hihoCoder挑战赛28 题目3 : 树的方差

    题目3 : 树的方差 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 对于一棵 n 个点的带标号无根树,设 d[i] 为点 i 的度数. 定义一棵树的方差为数组 d[1. ...

  4. hihoCoder挑战赛28 题目2 : 二进制翻转

    题目2 : 二进制翻转 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 定义函数 Rev(x) 表示把 x 在二进制表示下翻转后的值 例如: Rev(4)=1,因为 4 ...

  5. hihoCoder挑战赛28 题目1 : 异或排序

    题目1 : 异或排序 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个长度为 n 的非负整数序列 a[1..n] 你需要求有多少个非负整数 S 满足以下两个条件: ...

  6. hihoCoder挑战赛27题目一 福字 (dp)

    题目: 一个n × n的矩阵,其中每个位置都是一个非负整数. 一个福字被定义成是大小为 k 的正方形,满足其中的每个位置上的数都恰好比他的左边的那个和上边的那个大1(如果左边或上边的那个不存在的话就无 ...

  7. hihoCoder挑战赛11 A 随机斐波那契

    算了前三项.....发现是个大水题...   #include<stdio.h> int main() { int n; while (~scanf("%d", &am ...

  8. 【hihocoder1167】高等理论计算机科学 (重链剖分 +树状数组)

    Descroption 原题链接给你一棵\(~n~\)个点的树和\(~m~\)条链,求两两相交的链有多少对,两条链相交当且仅当有至少一个公共点.\(~1 \leq n, m \leq 10 ^ 5~\ ...

  9. hihoCoder挑战赛23

    hihoCoder挑战赛23 A.Emulator 题意 给一张图,有\(N(N \le 300)\)个点, 给出任意两点之间的最短路. 求最多可以去掉多少条边,使得任意两点的最短路长度不变. 思路 ...

随机推荐

  1. 单向关系中的JoinColumn

    1.person与address的一对一单向关系: 在address中没有特殊的注解. 在Person中对应到数据库里面就有一个指向Address的外键. 我们也可以增加注释指定外键的列的名字,如下: ...

  2. Server 对象

    如何解决Response.Redirect方法传递汉字丢失或乱码问题? 为了确保传递的汉字被正确地接收,可以在传值之前使用Server对象的UrlEncode方法对所传递的汉字进行URL编码.代码如下 ...

  3. 理解和使用 JavaScript 中的回调函数

    理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报  分类: JavaScript(4)    目录( ...

  4. Objective -C学习笔记 之copy(复制)

    //自定义类对象实现copy需要遵守copy协议(否则程序崩溃),实现必须实现的协议方法,里面的代码就决定了你的copy是深是浅 #import <Foundation/Foundation.h ...

  5. js005-引用类型

    js005-引用类型 数据类型分为基本类型和引用类型:基本类型值如下:Undefined.Null.Bollean.Number.String 本章内容: 1.使用对象 2.创建并操作数组 3.理解基 ...

  6. css014 响应式web设计

    css014 响应式web设计 一.    响应式web设计基础知识 1.rwd的三大理念:a.用于布局的弹性网络, b.用于图片和视频的弹性媒体,c.为不同屏幕宽度创建的不同样式的css媒体查询. ...

  7. css002 创建样式和样式表

    创建样式和样式表 一个样式表包含多个样式 样式表的种类 1.内部样式表,存放在<head></head>之间.如: <head> <style>   ( ...

  8. Linux 下 Oracle 内核参数优化

    数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块.而操作系统则是Oracle稳定运行与最大化性能的基石.本文主要描述基于Linux系统下 Or ...

  9. phpspidercookie

    <?php /** * Created by PhpStorm. * User: brady * Date: 2016/12/9 * Time: 17:32 */ ini_set("m ...

  10. python数据库操作常用功能使用详解(创建表/插入数据/获取数据)

    实例1.取得MYSQL版本 复制代码 代码如下: # -*- coding: UTF-8 -*-#安装MYSQL DB for pythonimport MySQLdb as mdbcon = Non ...