lca专题二
HDU 5293
题目要求
给你一棵树,树上有n个点。
然后给你m条链,每条链都有权值,然后让你选择一些不相交的链,使得权值和最大。
参考AC代码
|
|
思路
lca+树形dp+树状数组
要求权值最大,按照树形dp的思路去考虑,用dp[i]表示以第i个点为根节点的子树的最优解。
dp[i]的状态转移公式,有两种可能,第一种:第i个节点上不出现链,那么dp[i]=∑(dp[k] | k为i的子节点);
第二种:第i个节点上出现链,如果选择加入这条链,那么dp[i]=w(链的权值)+∑(dp[k] | k为链上的节点的子节点)=w+∑(sum[k] | k为链上的节点 )-∑(dp[k] | k为链上的节点)
sum[i]表示i节点的所有子节点的dp和,在 ∑(sum[k] | k为链上的节点 ) - ∑(dp[k] | k为链上的节点) 中减去的dp[k]会由它的父节点的sum补全。这样就得到了状态转移公式。
所减去的地方:sum[k] - dp[k]用树状数组维护
注意dfs序区间的开闭问题:out[x]+1
HDU 5296
题目要求
一棵树 n个点 有边权 q次操作
1 x:把点x加入到集合s中(若点x不在集合中)
2 x:把点x移除集合s(若点x在集合中)
对于每次询问 输出为了使集合S中所有的点联通需要最少的边权
参考AC代码
|
|
思路
lca+dfs序
对于添加或者删除一个点造成的影响有公式:dis[x]+dis[lca(a,b)]-dis[lca(x,a)]-dis[lca(x,b)]
a是dfs序大于x的点 b是dfs序小于x的点 若ab不同时存在 找到字典序最大和最小的点a和b即可
公式画图即可理解
寻找大于x和小于x的dfs序的点用set存dfs序后二分查找
注意添加和删除中ans更新的顺序
额外补充:
c.begin() 返回一个迭代器,它指向容器c的第一个元素
c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置
c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素
c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素前面的位置
cf gym 100015
题目要求
n点n边 无向图 正边权
问任意两点的最短距离
参考AC代码
|
|
思路
随便找一个环,然后在这个环上随便去掉一条边,然后就比较这个树上的距离小,还是经过这条边的饿距离小 一共就三条路径
比如你去掉的边是a,b,边权是w,你查询u,v
那么你比较dis(u,v),dis(u,a)+w+dis(b,v),dis(u,b)+w+dis(a,u)就好了
找环上的边,用并查集
cdoj 92
题目要求
给你一棵树,有边权,然后加了一条边,给Q次询问,问你这些点之间的最短距离缩短了多少
缩短为负输出0
思路
和上题类似 只需要询问部分改成
cf 575b
题目要求
在一棵树上,有一些边是单向边,有一些是双向边。如果逆向行驶单向边,第一次逆行这条边,罚款1,……第i次罚款2^i.
然后给出k个点,分别为ki,到达ki后再去ki+1,初始的时候在1点。问按照上面的安排,最少被罚多少。mod10^9+7
参考AC代码
|
|
思路
本题实质是记录每条路径反向经过的次数 然后快速幂统计答案
通过权值0 1 -1的赋值和up数组的对反 最后实现的结果是:
双向边依旧为0 单向边如果路径朝上 w=1 如果朝下 w=-1
cnt[0][]记录的是朝上的路径 cnt[1][]记录的是朝下的路径
最后等价于up=-1的点统计cnt[0][i]的路径条数 up=0的点统计cnt[1][i]的路径条数
从a->b,可以拆分成a->lca(a,b)+lca(a,b)->b,每次a++,lca(a,b)– b++,lca(a,b)–
dfs2统计计算出所有结点下(相当于统计每条边的贡献)的cnt[0][]和cnt[1][] 若up[i]不等于0 快速幂更新答案