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~】

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. using namespace std;
  5. typedef long long LL;
  6. #define MAXN 100010
  7. struct Edge {
  8. int to, next;
  9. } edge[MAXN << ];
  10. struct Node {
  11. int to, next, num;
  12. } Query[MAXN << ];
  13. struct node {
  14. int u, v, lca;
  15. } input[MAXN];
  16. int totEdge, totQuery, n, m;
  17. int headEdge[MAXN], headQuery[MAXN];
  18. int ancestor[MAXN], father[MAXN], LCAnum[MAXN], sum[MAXN];
  19. bool vis[MAXN];
  20. void addEdge(int from, int to) {
  21. edge[totEdge].to = to;
  22. edge[totEdge].next = headEdge[from];
  23. headEdge[from] = totEdge++;
  24. }
  25. void addQuery(int from, int to, int x) {
  26. Query[totQuery].to = to;
  27. Query[totQuery].num = x;
  28. Query[totQuery].next = headQuery[from];
  29. headQuery[from] = totQuery++;
  30. }
  31. void init() {
  32. memset(headEdge, -, sizeof(headEdge));
  33. memset(headQuery, -, sizeof(headQuery));
  34. memset(father, -, sizeof(father));
  35. memset(vis, false, sizeof(vis));
  36. memset(sum, , sizeof(sum));
  37. memset(LCAnum, , sizeof(LCAnum));
  38. totEdge = totQuery = ;
  39. }
  40. int find_set(int x) {
  41. if(x == father[x]) return x;
  42. else return father[x] = find_set(father[x]);
  43. }
  44. void union_set(int x, int y) {
  45. x = find_set(x); y = find_set(y);
  46. if(x != y) father[y] = x;
  47. }
  48. void Tarjan(int u) {
  49. father[u] = u;
  50. for(int i = headEdge[u]; i != -; i = edge[i].next) {
  51. int v = edge[i].to;
  52. if(father[v] != -) continue;
  53. Tarjan(v);
  54. union_set(u, v);
  55. }
  56. for(int i = headQuery[u]; i != -; i = Query[i].next) {
  57. int v = Query[i].to;
  58. if(father[v] == -) continue;
  59. input[Query[i].num].lca = find_set(v);
  60. }
  61. }
  62. void DFS(int u, int pre) {
  63. vis[u] = ;
  64. sum[u] = sum[pre] + LCAnum[u];
  65. for(int i = headEdge[u]; i != -; i = edge[i].next) {
  66. int v = edge[i].to;
  67. if(vis[v]) continue;
  68. DFS(v, u);
  69. }
  70. }
  71. int main() {
  72. init();
  73. scanf("%d%d", &n, &m);
  74. for(int i = ; i < n - ; i++) {
  75. int a, b;
  76. scanf("%d%d", &a, &b);
  77. addEdge(a, b); addEdge(b, a);
  78. }
  79. for(int i = ; i < m; i++) {
  80. int a, b;
  81. scanf("%d%d", &a, &b);
  82. input[i].u = a, input[i].v = b;
  83. addQuery(a, b, i); addQuery(b, a, i);
  84. }
  85. Tarjan();
  86. for(int i = ; i < m; i++)
  87. LCAnum[input[i].lca]++;
  88. DFS(, );
  89. LL ans = ;
  90. for(int i = ; i < m; i++) {
  91. ans += (sum[input[i].u] + sum[input[i].v] - * sum[input[i].lca]);
  92. }
  93. for(int i = ; i <= n; i++) {
  94. ans += (LL)LCAnum[i] * (LCAnum[i] - ) / ;
  95. }
  96. printf("%lld\n", ans);
  97. return ;
  98. }

转载:)

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. 如何保持自己 fork 的项目和原始项目同步

    首先先通过 github 的 web 页面 fork 目标的项目 前提是自己已经设置好了git,并且配置了相应的权限 然后使用git clone命令在本地克隆自己 fork 的项目: git clon ...

  2. UEditor上传图片到七牛云储存(c#)

    我们的网站一般放在虚拟空间或者服务器上,图片如果存在本地目录,会占用很多空间和流量,还增加了负担,好的办法是把图片存放到云储存服务里面,平时用url去拿 云储存:普遍说又拍云和七牛比较好,看到七牛免费 ...

  3. C#6.0特性笔记

    Visual Studio 2015的C#6.0,今天无意中看这个视频,怕忘记其中的特性,故此进行记录. public class Point { //Getter专属自动属性 public int ...

  4. Ubuntu 之 Personal Package Archive (PPA)

    How do I use software from a PPA? To start installing and using software from a Personal Package Arc ...

  5. 《JavaScript权威指南》学习笔记 第四天 数组

    昨天学习了js的对象,了解了js的原型链.在js里面万事万物皆对象,只不过一些原始类型要经过包装对象的包装才能暂时变为对象.数组的本质是什么呢?数组其实就是一组数,也就是链表.每个数只是这个链表上的一 ...

  6. DOM参考手册及事件参考手册

    给全局HTML DOM元素增加函数的方法 HTMLElement.prototype.hasClass = function (className) { return new RegExp(" ...

  7. zabbix监控系列(1)之zabbix-server安装

    推荐使用yum来安装 第一步:LAMP平台 zabbix使用php开发的,所以依赖于LAMP或者LNMP平台,由于http+mysql用yum安装及其方便,所以我在这里使用yum安装. yum -y ...

  8. JQuery 和JavaScript的区别

    Google提供的jquery包: http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js jQuery官方的jquery包: ...

  9. Objective-C 中的类和对象

    http://blog.ibireme.com/2013/11/25/objc-object/ Objective-C的runtime是开源的,源码可以在苹果官网下载到:objc4. 在objc4-5 ...

  10. c# 操作datatable

    1.创建 datatable DataTable dt=new Datable();// 可以给表创建一个名字,tb 2.给表加个列名: dt.Columns.Add("id", ...