题解

首先如果我们要确定出每个\(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的更多相关文章

  1. Codeforces 1140G Double Tree 倍增 + dp

    刚开始, 我以为两个点肯定是通过树上最短路径过去的, 无非是在两棵树之间来回切换, 这个可以用倍增 + dp 去维护它. 但是后来又发现, 它可以不通过树上最短路径过去, 我们考虑这样一种情况, 起点 ...

  2. @hdu - 6594@ Double Tree

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定两棵 N 个点的树,以及树上每条边的权值 w(u, v),每 ...

  3. Codeforces 68D - Half-decay Tree

    题意 有一颗高度为 \(h\) 的完全二叉树(即点数为 \(2^{h+1}-1\) ),有两种操作: add x y 给 \(x\) 点的权值加 \(y\) decay 一次衰变定义为选择一个叶子节点 ...

  4. 平衡树 替罪羊树(Scapegoat Tree)

    替罪羊树(Scapegoat Tree) 入门模板题 洛谷oj P3369 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入xx数 删除xx数(若有多个相同 ...

  5. Color a Tree

    题目链接:Click here Solution: 看起来不太能dp,则考虑树上贪心 题目要求一个点必须先染父亲才能染自己,就给了我们启示,贪心的合并点 我们定义一个点的权重为这个点的价值和/点数,然 ...

  6. CodeForces 602E【概率DP】【树状数组优化】

    题意:有n个人进行m次比赛,每次比赛有一个排名,最后的排名是把所有排名都加起来然后找到比自己的分数绝对小的人数加一就是最终排名. 给了其中一个人的所有比赛的名次.求这个人最终排名的期望. 思路: 渣渣 ...

  7. Educational Codeforces Round 62 (Rated for Div. 2) Solution

    最近省队前联考被杭二成七南外什么的吊锤得布星,拿一场Div. 2恢复信心 然后Div.2 Rk3.Div. 1+Div. 2 Rk9,rating大涨200引起舒适 现在的Div. 2都怎么了,最难题 ...

  8. poj 1151 (未完成) 扫描线 线段树 离散化

    #include<iostream> #include<vector> #include<cmath> #include<algorithm> usin ...

  9. codeforce 139E

    成段更新+离散化才能过,数据好强.. 单点更新挂在了test27,下次做到成段更新再来做! /* 期望=存活概率*点权值/100 ans=sum(期望) 离散化树木权值,数轴统计累加可能倒下的树木概率 ...

随机推荐

  1. Myeclipse配置jad

    下载地址:http://pan.baidu.com/s/1bnpMEuF 1.下载jad158g.win.zip 下载后解压.解压缩后将jad.exe拷贝到自定义的文件夹内:我这里用的是D:/jad/ ...

  2. 使用Spring定时任务并且通过AOP监控任务执行情况

    原文:http://www.open-open.com/code/view/1426250803279 本文讲的是通过Spring注解的方式实现任务调度.只要引入了spring-context包就能够 ...

  3. jmeter的master远程运行和停止slave

    jmeter可以部署成master-slave或者叫client-server模式,一个master(client)可以同时控制多个slave(server). 在linux系统下,master(cl ...

  4. 【网络】TCP的流量控制

    一.利用滑动窗口实现流量控制 流量控制是让发送方的发生速率不要太快,要让接收方来得及接收. 发送方的发送窗口不能超过接收方给出的接收窗口的数值,TCP的窗口单位是字节,不是报文段. TCP为每一个连接 ...

  5. Java多线程导致的的一个事物性问题

    业务场景 我们如今有一个类似于文件上传的功能.各个子网站接受业务,业务上传文件,各个子网站的文件须要提交到总网站保存.文件是按批次提交到总网站的,也就是说,一个批次以下约有几百个文件. 考虑到白天提交 ...

  6. Java第二次作业參考代码

    Java第二次作业參考代码 [程序11] 题目:有1.2.3.4四个数字,能组成多少个互不同样且无反复数字的三位数?都是多少? public class lianxi11 { public stati ...

  7. PHPCMS中GET标签概述、 get 标签语法、get 标签创建工具、get 调用本系统演示样例、get 调用其它系统演示样例

    一.get 标签概述 通俗来讲,get 标签是Phpcms定义的能直接调用数据库里面内容的简单化.友好化代码,她可调用本系统和外部数据,仅仅有你对SQL有一定的了解,她就是你的绝世好剑!也就是适合熟悉 ...

  8. java SE基础(Collection接口概述)

    Collection接口相关集成关系例如以下图 1. 关于可迭代接口(Iterable)             可迭代接口仅包括一个方法,返回一个在一组T类型元素上进行迭代的迭代器: public ...

  9. 【转】SQL中的取整函数FLOOR、ROUND、CEIL、TRUNC、SIGN

    --------------------------------------------------------------------------1 trunc(value,precision)按精 ...

  10. C++对象模型——解构语意学(第五章)

    5.4    对象的效率 (Object Efficiency) 在下面的效率測试中,对象构造和拷贝所须要的成本是以Point3d class声明为基准,从简单形式逐渐到复杂形式,包含Plain Ol ...