码迷,mamicode.com
首页 > 编程语言 > 详细

$ [ZJOI2019] $语言

时间:2019-10-04 22:41:07      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:题目   连通   节点   块大小   表示   sum   dfs   排序   mat   

~~ 话说,本题考场想出三只\(log\)的暴力做法,被卡成暴力了。~~

题目分析

首先考虑枚举每一个点,计算这个点可以和多少点进行交易。

将所有经过该点的路径\(s,t\)拿出,那么这些极远的\(s,t\)构成的连通块大小\(sz - 1\)就是答案。

\(Codeforces\)\(异象石\)那题可以想到,若一些点集按照\(dfs\)序排序,那么这些点构成连通块大小就是

\(\frac{1}{2} (dist(a_1 , a_2) + dist(a_2,a_3) + ... + dist(a_{k-1} , a_k) + dist(a_k,a_1))\)

考虑对于每一个节点开一棵线段树,其叶子节点\(i\)表示\(dfs\)序为\(i\)的极远点出现次数。

线段树中存储\(3\)个值\(lp,rp,Sum\)分别表示当前存在的大于\(0\)的最小下标和最大下标,和不算头尾的连通块大小。

由于路径条数为\(m\),显然我们可以用可持久化线段树来维护这\(n\)棵线段树,使得空间复杂度为\(O(m log_2 n)\)

利用树上差分的思想,对于每一条\(s,t\)的路径,我们先在\(s\)\(t\)所在的线段树中将\(dfn[s]\)\(dfn[t]\)两个点单点\(+1\)

然后在\(father(lca(s,t))\)的节点,将\(dfn[s]\)\(dfn[t]\)两个点单点\(-2\)

于是,我们可以自下往上去统计每个节点的答案。

每一次,我们需要对该节点的所有子树进行线段树合并,然后询问这个节点的答案,将其累加进总个数中。

这样,我们就完成了无序数对的统计,那么此时答案除以\(2\)就是最终的答案。

复杂度分析

由于\(n\)次线段树合并节点总数是\(m\)个,所以需要时间复杂度为\(O(m log_2 n)\)

由于\(m\)次线段单点修改,使用\(O(1)\)\(LCA\)实现,所以需要时间复杂度为\(O(m log_2 n)\)

所以,本题的总时间复杂度就是\(O(m log_2 n)\)

$ [ZJOI2019] $语言

标签:题目   连通   节点   块大小   表示   sum   dfs   排序   mat   

原文地址:https://www.cnblogs.com/ljc20020730/p/11623520.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!