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(期望) 离散化树木权值,数轴统计累加可能倒下的树木概率 ...
随机推荐
- Linux命令chattr和lsattr
先看字面解释: chattr:chattr - change file attributes on a Linux file system lsattr - list file attributes ...
- ThoughtWorks技术雷达
ThoughtWorks技术雷达 技术成熟方案的一个推荐网站.
- Visual Studio VS如何拷贝一个项目的窗体文件到另一个项目
1 比如下我有一个项目,我要把这个Config整个窗体和代码拷贝到另一个项目 2 在新项目中添加现有项,然后把这个窗体相关的三个文件都添加到新的项目中 3 然后在新窗体中就什么都有了 ...
- javascript/jquery模板引擎——Handlebars初体验
Handlebars.js下载地址:http://handlebarsjs.com/ 最近自己在建一个站,采用完全的前后端分离的方式,现在正在做前端的部分.其中有项功能是需要ajax调用后端接口,返回 ...
- (2)mac下安装MySql数据库软件
一,软件下载: https://dev.mysql.com/downloads/mysql/ 也可以从其他资源下载.不一定非要官方下载 二,安装 这个比较简单,之间双击开启安装程序,一直下一步就可以. ...
- (16)ServletContext详解
1,作用: ServletContext对象 ,叫做Servlet的上下文对象.表示一个当前的web应用环境.一个web应用中只有一 ...
- 网络编程-获取ip-解析ip
import java.net.InetAddress; import java.net.UnknownHostException; /** * 查询ip地址 * * @author chengluc ...
- Lightoj 1023 - Discovering Permutations
1023 - Discovering Permutations PDF (English) Statistics Forum Time Limit: 0.5 second(s) Memory L ...
- Ubuntu linux 返回上一次访问的目录
cd - (cd空格 减号)返回最近一次访问的目录 这个非常方便.平时经常用终端切换目录,能够方便地回到原来的目录就很爽了. jiqing@jiqing-pad:/usr/local/redis/sr ...
- hdu 2476 (string painter) ( 字符串刷子 区间DP)
String painter Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...