CF1140G Double Tree

题解
首先如果我们要确定出每个\(dis_{i \to i+1 , i \in odd}\)
这个可以用两遍树形\(DP\)来解决
一遍是考虑走子树子树绕过来的
一遍是考虑从走祖先绕过来的
然后就可以考虑用倍增来解决了
设\(st1[u][i][0/1][0/1]\)表示从点\(u\)开始向上跳\(2^j\)步,开始的位置位于左/右边的树,结束的位置位于左/右边的树
倍增的时候就用两个数组\(dp1[0/1]/dp2[0/1]\)表示从\(u/v\)到左/右边树的\(LCA\)
不断往上跳着更新即可
注意要先把\(dp1/dp2\)的数组的值记录下来再用记录的值更新==
代码
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define LL long long
const int M = 300005 ;
const LL INF = 1e18 ;
using namespace std ;
inline LL read() {
char c = getchar() ; LL x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , lg[M] , dep[M] ;
LL w[M] , st[M][22] , st1[M][22][2][2] , dp1[2] , dp2[2] ;
struct Node { int v ; LL w1 , w2 ; } ;
vector < Node > vec[M] ;
void dfs1(int u , int father) {
LL w1 , w2 ;
st[u][0] = father ; dep[u] = dep[father] + 1 ;
for(int i = 0 , v ; i < vec[u].size() ; i ++) {
v = vec[u][i].v , w1 = vec[u][i].w1 , w2 = vec[u][i].w2 ;
if(v == father) continue ; dfs1(v , u) ;
w[u] = min( w[u] , w[v] + w1 + w2 ) ;
}
}
void dfs2(int u , int father) {
LL w1 , w2 ;
for(int i = 0 , v ; i < vec[u].size() ; i ++) {
v = vec[u][i].v , w1 = vec[u][i].w1 , w2 = vec[u][i].w2 ;
if(v == father) continue ;
w[v] = min( w[v] , w[u] + w1 + w2 ) ;
dfs2(v , u) ;
}
}
void dfs(int u , int father) {
LL w1 , w2 ;
for(int i = 0 , v ; i < vec[u].size() ; i ++) {
v = vec[u][i].v , w1 = vec[u][i].w1 , w2 = vec[u][i].w2 ;
if(v == father) continue ;
dfs(v , u) ;
st1[v][0][0][0] = min( w1 , w[v] + w2 + w[u] ) ;
st1[v][0][1][1] = min( w2 , w[u] + w1 + w[v] ) ;
st1[v][0][0][1] = min( w[v] + w2 , w1 + w[u] ) ;
st1[v][0][1][0] = min( w2 + w[u] , w[v] + w1 ) ;
}
}
inline int LCA(int u , int v) {
if(dep[u] < dep[v]) swap(u , v) ;
for(int i = lg[n] ; i >= 0 ; i --) if(dep[st[u][i]] >= dep[v]) u = st[u][i] ;
if(u == v) return u ;
for(int i = lg[n] ; i >= 0 ; i --) if(st[u][i] != st[v][i]) u = st[u][i] , v = st[v][i] ;
return st[u][0] ;
}
inline LL Solve(int x , int y) {
int u = ((x + 1) >> 1) , v = ((y + 1) >> 1) , lcap ;
if(dep[u] < dep[v]) {
swap(u , v) ;
swap(x , y) ;
}
lcap = LCA(u , v) ;
LL tp0 , tp1 ;
dp1[(x + 1) & 1] = 0 ; dp1[((x + 1) & 1) ^ 1] = w[u] ;
for(int i = lg[n] ; i >= 0 ; i --) {
if(dep[st[u][i]] >= dep[lcap]) {
tp0 = dp1[0] ; tp1 = dp1[1] ;
dp1[0] = min( tp0 + st1[u][i][0][0] , tp1 + st1[u][i][1][0] ) ;
dp1[1] = min( tp0 + st1[u][i][0][1] , tp1 + st1[u][i][1][1] ) ;
u = st[u][i] ;
}
}
u = v ;
dp2[(y + 1) & 1] = 0 ; dp2[((y + 1) & 1) ^ 1] = w[u] ;
for(int i = lg[n] ; i >= 0 ; i --) {
if(dep[st[u][i]] >= dep[lcap]) {
tp0 = dp2[0] , tp1 = dp2[1] ;
dp2[0] = min( tp0 + st1[u][i][0][0] , tp1 + st1[u][i][1][0] ) ;
dp2[1] = min( tp0 + st1[u][i][0][1] , tp1 + st1[u][i][1][1] ) ;
u = st[u][i] ;
}
}
return min(dp1[0] + dp2[0] , dp1[1] + dp2[1]) ;
}
int main() {
n = read() ;
for(int i = 2 ; i <= n ; i ++) lg[i] = lg[i >> 1] + 1 ;
for(int i = 1 ; i <= n ; i ++) w[i] = read() ;
LL w1 , w2 ;
for(int i = 1 , u , v ; i < n ; i ++) {
u = read() ; v = read() ; w1 = read() ; w2 = read() ;
vec[u].push_back( (Node) { v , w1 , w2 } ) ;
vec[v].push_back( (Node) { u , w1 , w2 } ) ;
}
memset(st1 , 31 , sizeof(st1)) ;
dfs1(1 , 0) ; dfs2(1 , 0) ; dfs(1 , 0) ;
for(int j = 1 ; j <= lg[n] ; j ++)
for(int u = 1 ; u <= n ; u ++) {
st[u][j] = st[st[u][j - 1]][j - 1] ;
st[u][j] = st[st[u][j - 1]][j - 1] ;
st1[u][j][0][0] = min( st1[u][j - 1][0][0] + st1[st[u][j - 1]][j - 1][0][0] , st1[u][j - 1][0][1] + st1[st[u][j - 1]][j - 1][1][0] ) ;
st1[u][j][0][1] = min( st1[u][j - 1][0][0] + st1[st[u][j - 1]][j - 1][0][1] , st1[u][j - 1][0][1] + st1[st[u][j - 1]][j - 1][1][1] ) ;
st1[u][j][1][0] = min( st1[u][j - 1][1][0] + st1[st[u][j - 1]][j - 1][0][0] , st1[u][j - 1][1][1] + st1[st[u][j - 1]][j - 1][1][0] ) ;
st1[u][j][1][1] = min( st1[u][j - 1][1][0] + st1[st[u][j - 1]][j - 1][0][1] , st1[u][j - 1][1][1] + st1[st[u][j - 1]][j - 1][1][1] ) ;
}
int Q = read() , x , y ;
while(Q --) {
x = read() ; y = read() ;
printf("%lld\n",Solve(x , y)) ;
}
return 0 ;
}
CF1140G Double Tree的更多相关文章
- Codeforces 1140G Double Tree 倍增 + dp
刚开始, 我以为两个点肯定是通过树上最短路径过去的, 无非是在两棵树之间来回切换, 这个可以用倍增 + dp 去维护它. 但是后来又发现, 它可以不通过树上最短路径过去, 我们考虑这样一种情况, 起点 ...
- @hdu - 6594@ Double Tree
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定两棵 N 个点的树,以及树上每条边的权值 w(u, v),每 ...
- Codeforces 68D - Half-decay Tree
题意 有一颗高度为 \(h\) 的完全二叉树(即点数为 \(2^{h+1}-1\) ),有两种操作: add x y 给 \(x\) 点的权值加 \(y\) decay 一次衰变定义为选择一个叶子节点 ...
- 平衡树 替罪羊树(Scapegoat Tree)
替罪羊树(Scapegoat Tree) 入门模板题 洛谷oj P3369 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入xx数 删除xx数(若有多个相同 ...
- Color a Tree
题目链接:Click here Solution: 看起来不太能dp,则考虑树上贪心 题目要求一个点必须先染父亲才能染自己,就给了我们启示,贪心的合并点 我们定义一个点的权重为这个点的价值和/点数,然 ...
- CodeForces 602E【概率DP】【树状数组优化】
题意:有n个人进行m次比赛,每次比赛有一个排名,最后的排名是把所有排名都加起来然后找到比自己的分数绝对小的人数加一就是最终排名. 给了其中一个人的所有比赛的名次.求这个人最终排名的期望. 思路: 渣渣 ...
- Educational Codeforces Round 62 (Rated for Div. 2) Solution
最近省队前联考被杭二成七南外什么的吊锤得布星,拿一场Div. 2恢复信心 然后Div.2 Rk3.Div. 1+Div. 2 Rk9,rating大涨200引起舒适 现在的Div. 2都怎么了,最难题 ...
- poj 1151 (未完成) 扫描线 线段树 离散化
#include<iostream> #include<vector> #include<cmath> #include<algorithm> usin ...
- codeforce 139E
成段更新+离散化才能过,数据好强.. 单点更新挂在了test27,下次做到成段更新再来做! /* 期望=存活概率*点权值/100 ans=sum(期望) 离散化树木权值,数轴统计累加可能倒下的树木概率 ...
随机推荐
- 从头开始学Android之(一)——— Android架构
从事Android开发已经两年多了,最近项目上特别清闲,刚开始时在闲暇的时候都不知道干嘛,整天混日子.有一天突然有个以前同学找到我,说要我帮忙做一个Android的需求,就是在后台截屏(涉及到服务以及 ...
- chrome插件vimium的安装和使用
vimium工具的作用:使你脱离鼠标,使用键盘方便操作页面,默认对所有网站生效 1.chrome商店里有的,但是,我怎么安装,都不行 2.源码安装:http://vimium.github.io/ h ...
- 解决安装oracle11g r2时提示pdksh conflicts with ksh-20100621-2.el6.i686问题
http://blog.csdn.net/linghao00/article/details/7943740 http://www.2cto.com/os/201306/218566.html 在Ce ...
- 【转】C++函数的重载、覆盖和隐藏区别
网上看到的关于C++函数的重载.覆盖和隐藏区别的回答,如下(其内容来源于C++面试宝典中一道题目): a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:( ...
- linux上安装启动elasticsearch-5.5.1完整步骤
linux上安装启动elasticsearch-5.5.1完整步骤 学习了:https://blog.csdn.net/hingcheung/article/details/77144574 http ...
- HDU1306 String Matching 【暴力】
String Matching Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 一个关于MYSQL IFNULL的用法
select a.receiveID,(a.num - IFNULL(b.num,0)) as num from (SELECT num,receiveID from dog_giftnumrecor ...
- C++实现KMP模式匹配算法
#include<iostream> #include<string> #include<vector> using namespace std; void Nex ...
- Android实战简易教程-第四十枪(窃听风云之短信监听)
近期在做监听验证码短信自己主动填入的功能,无意间想到了一个短信监听的办法. 免责声明:短信监听本身是一种违法行为,这里仅仅是技术描写叙述.请大家学习技术就可以.(哈哈) 本实例是基于bmob提供的后台 ...
- HDU 1015 Safecracker(第一次用了搜索去遍历超时,第二次用for循环能够了,思路一样的)
Safecracker Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total S ...