hihoCoder挑战赛11.题目4 : 高等理论计算机科学(LCA)
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)的更多相关文章
- 【Hihocoder 1167】 高等理论计算机科学 (树链的交,线段树或树状数组维护区间和)
[题意] 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 少女幽香这几天正在学习高等理论计算机科学,然而她什么也没有学会,非常痛苦.所以她出去晃了一晃,做起了一些没什么意 ...
- [题解]hihoCoder挑战赛18——题目1 神奇字符串
题目地址:http://hihocoder.com/problemset/problem/1264 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 我们说两个字符串是非常 ...
- hihoCoder挑战赛28 题目3 : 树的方差
题目3 : 树的方差 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 对于一棵 n 个点的带标号无根树,设 d[i] 为点 i 的度数. 定义一棵树的方差为数组 d[1. ...
- hihoCoder挑战赛28 题目2 : 二进制翻转
题目2 : 二进制翻转 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 定义函数 Rev(x) 表示把 x 在二进制表示下翻转后的值 例如: Rev(4)=1,因为 4 ...
- hihoCoder挑战赛28 题目1 : 异或排序
题目1 : 异或排序 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个长度为 n 的非负整数序列 a[1..n] 你需要求有多少个非负整数 S 满足以下两个条件: ...
- hihoCoder挑战赛27题目一 福字 (dp)
题目: 一个n × n的矩阵,其中每个位置都是一个非负整数. 一个福字被定义成是大小为 k 的正方形,满足其中的每个位置上的数都恰好比他的左边的那个和上边的那个大1(如果左边或上边的那个不存在的话就无 ...
- hihoCoder挑战赛11 A 随机斐波那契
算了前三项.....发现是个大水题... #include<stdio.h> int main() { int n; while (~scanf("%d", &am ...
- 【hihocoder1167】高等理论计算机科学 (重链剖分 +树状数组)
Descroption 原题链接给你一棵\(~n~\)个点的树和\(~m~\)条链,求两两相交的链有多少对,两条链相交当且仅当有至少一个公共点.\(~1 \leq n, m \leq 10 ^ 5~\ ...
- hihoCoder挑战赛23
hihoCoder挑战赛23 A.Emulator 题意 给一张图,有\(N(N \le 300)\)个点, 给出任意两点之间的最短路. 求最多可以去掉多少条边,使得任意两点的最短路长度不变. 思路 ...
随机推荐
- C#用HttpClient抓取jd.com搜索框下拉数据
添加System.Web.dll引用 添加System.Net.Http引用 using System.Net.Http; using System.Web; string key = "电 ...
- Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property 'xxx': no matching editors or conversion strategy found
今天在完成项目的时候遇到了下面的异常信息: 04-Aug-2014 15:49:27.894 SEVERE [http-apr-8080-exec-5] org.apache.catalina.cor ...
- Python编码格式的指定方式
参考自: http://python.jobbole.com/85852/, 原文探究的更深,有兴趣的可以去看看. 简介来讲就是使用一种特殊的注释来声明编码格式,如何判断这种格式也用了很简单粗暴有效的 ...
- ARPSpoofing教程(三) - 捕获数据包
1: #include"pcap.h" 2: //每次捕获到数据包时,libpcap都会自动调用这个回调函数 3: void packet_handler(u_char *para ...
- 01C语言基础知识
C语言知识要点总结 1在C语言中,关系运算的结果为“真”,就返回1,"假"就返回0 printf("input value is %d" , 5 > 4) ...
- linux系统性能监视命令
preface as a linux engineer,you should know how to use these command of monitor system,so let's lear ...
- centos忘记root密码,重新设置的方法
今天重新装了一个centos6.6,好像root密码没有叫我设置吧,然后用虚拟机开始安装之前的密码登录显示失败,所以有了下面的彩蛋.....Helloween... 在虚拟机安装了Centos,今天要 ...
- Django中Celery的实现介绍(一)
Django中Celery的实现 Celery官网http://www.celeryproject.org/ 学习资料:http://docs.jinkan.org/docs/celery/ Cele ...
- android语音识别和合成第三方 .
讯飞语音云 http://open.voicecloud.cn/index.php 目前支持6大类型的SDK下载,包括Android. iPhone平台移动应用的接入,Windows.Linux平台P ...
- ubuntu下samba服务器的安装与配置
参考网址:http://jingyan.baidu.com/album/00a07f38b9194082d028dc08.html?picindex=9 sudo service smbd resta ...