[APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话: 考虑到安全因素,选择的路径经过同一个点至多一次. 换句话说就是简单路径,用(广义)圆方树的基本条件已经满足,可以把问题变到树上:令方点的权值为所在点双的大小,圆点会被算重所以点权为\(-1\),统计任意两点间的点权和就好了.直接做是\(n ^ 2\)的,考虑枚举每一个点看会产生多少贡献,对答案的…
Description ​ 给你一张\(~n~\)个点\(~m~\)条边的无向图,求有多少个三元组\(~(x, ~y, ~z)~\)满足存在一条从\(~x~\)到\(~z~\)并且经过\(~y~\)的路径.保证两点之间最多只有一条边连接. Solution ​ 考虑对这张图建圆方树,每个方点的权值记录该点双的点数,每个圆点的权值为\(-1\).这样先确定\(~x, ~z~\)之后, 其路径上的点权和就是满足条件的\(~y~\)的个数 (因为一个圆点的贡献会算进两个相邻的方点中,所以每个圆点的权值…
题目:https://loj.ac/problem/2587 先写了 47 分暴力. 对于 n<=50 的部分, n3 枚举三个点,把图的圆方树建出来,合法条件是 c 是 s -> f 路径上的方点连出去的某个圆点.像找 LCA 那样走一遍 s -> f 路径即可. 对于树的部分,考虑一条路径对答案的贡献是其边数减 1 ,所以对于每条边求一下它在多少路径中,就是 siz[ v ] * ( n-siz[ v ] ) ( v 是它指向的点),然后答案再减去 \( C_n^2 \) 即可. 注…
主要卡在一个结论上..关于点双有一个常用结论,也经常作为在圆方树/简单路径上的良好性质,对于任意点双内互不相同的三点$s,c,t$,都存在简单路径$s\to c\to t$,证明不会.可以参见clz博客..我就是跟着他学的 然后就好办了,转化为树上两点计经过点双内所有点个数,然后赋权后变为统计两两圆点对的路径权值和,这个就是一个树形DP,统计每个点作为圆点或者方点被所有路径经过多少次,加入答案.. 还是比较裸的,因为重点还在于这个很多题都出现到的点双的简单路径的性质.. #include<ios…
题目链接 洛谷P4630 题解 看了一下部分分,觉得树的部分很可做,就相当于求一个点对路径长之和的东西,考虑一下能不能转化到一般图来? 一般图要转为树,就使用圆方树呗 思考一下发现,两点之间经过的点双,点双内所有点一定都可以作为中介点 那么我们将方点赋值为点双大小,为了去重,剩余点赋值\(-1\) 答案就是任意两点间权值和之和 我们只需枚举每个点被经过多少次,这就很容易计算了 复杂度\(O(n)\) #include<algorithm> #include<iostream> #i…
圆方树大致理解:将每个点双看做一个新建的点(方点),该点双内的所有点(圆点)都向新建的点连边,最后形成一棵树,可以给点赋予点权,用以解决相关路径问题. 在本题中,方点点权赋值为该点双的大小,因为两个点双最多有一个交点,将圆点赋为-1来去重,先用tarjan()构建出圆方树,在跑一遍dfs,dfs枚举的是作为c的点,维护sz2[ ](圆点个数,因为s和f只能是圆点),利用乘法原理累加答案即可. 注意代码中累加答案是要乘2,(s和f可以交换). 1 #include<bits/stdc++.h>…
 [APIO2018] 铁人两项 题目大意: 给定一张图,问有多少三元组(a,b,c)(a,b,c 互不相等)满足存在一条点不重复的以a为起点,经过b,终点为c的路径 如果你不会圆方树 ----------------------- 放弃是最好的选择(先学了再来吧) 如果你会圆方树 考虑\((a,...,c)\) 1.如果a,c不同属一个点双,不难发现答案为路上经过的(点双的节点个数)的和减去割点数 2.如果a,c同属一个点双,那么答案为本点双的节点个数 - 2 自然地想到方点的权值为内含节点个…
题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方树,枚举中间点$b$,一对合法的$a,c$需要使这两个点位于与$b$直接相连的方点的不同子树中.树形$DP$,对圆点和方点分别统计答案即可. #include<set> #include<map> #include<queue> #include<stack>…
把这个图缩成圆方树,把方点的权值设成-1,圆点的权值设成点双的size,算 经过这个点的路径的数量*这个点的点权 的和即是答案. #include <iostream> #include <cstdio> #include <cstring> using namespace std; ; struct Edge{ int to[N],nxt[N],head[N],ecnt; Edge(){ecnt=;} void add(int bg,int ed) {nxt[++ec…
一道很好的圆方树入门题 感谢PinkRabbit巨佬的博客,讲的太好啦 首先是构建圆方树的代码,也比较好想好记 void tarjan(int u) { dfn[u] = low[u] = ++dfn_clk; //初始化dfn和low数组 stk[++tp] = u; //把u加入栈中 for(int i = head[u]; i; i = e[i].next) { int v = e[i].to; if(!dfn[v]) { //v还未访问 tarjan(v); //先访问 low[u] =…