1.易知,树上两点的距离dis[u][v] = D[u]+D[v]-2*D[lca(u,v)] (D为节点到根节点的距离)

2.某条边<u,v>权值一旦改变,将会影响所有以v为根的子树上的节点到根节点的距离,很明显,DFS一遍后以v为根的子树在DFS序列中是连续的一段,及转化为区间更新问题,可以用树状数组。

做法:先把求LCA解决,LCA可以转化为RMQ问题,可参见:LCA转RMQ, 即转化为LCA(T,u,v) = RMQ(B,pos[u],pos[v]),其中B为深度序列。预先DFS可以处理出深度序列,我这里用的是“另一种”深度序列,即时间戳表示的深度序列,用时间戳来代表深度,以及欧拉序列和pos数组,还有in[],out[]数组,表示每个节点DFS进出的时间戳。在DFS时间戳序列上建树状数组,值为每个节点与原来到根节点的距离相比的该变量。要用树状数组需要用一个巧妙的方法转为前缀和问题:在时间戳序列中,如果要更新v的子树,即为更新in[v],out[v],令a = in[v],b=out[v],则可以令A[a] = delta,A[b+1] = -delta。然后更新,就可以用树状数组来查询了。然后每次求两点间距离的时候,结果为固定的dis[u][v]+变动的值(树状数组query求出)。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 100007 struct Edge
{
int u,v,w,next;
}G[*N]; int first[N],tot,n,Time,ind,ola[*N],id;
int pos[N],in[*N],out[*N],vis[*N];
int d[*N][],dis[N],c[*N],T[*N],dp[*N]; void RMQ_init()
{
int i,j;
for(i=;i<=id;i++)
d[i][] = dp[i];
for(j=;(<<j)<=id;j++)
{
for(i=;i+(<<j)-<=id;i++)
d[i][j] = min(d[i][j-],d[i+(<<(j-))][j-]);
}
} int RMQ(int l,int r)
{
int k = ;
while((<<(k+)) <= r-l+)
k++;
return min(d[l][k],d[r-(<<k)+][k]);
} void addedge(int u,int v,int w)
{
G[tot].u = u;
G[tot].v = v;
G[tot].w = w;
G[tot].next = first[u];
first[u] = tot++;
} void init()
{
memset(G,,sizeof(G));
memset(first,-,sizeof(first));
memset(c,,sizeof(c));
memset(d,,sizeof(d));
tot = ;
Time = ;
ind = ;
id = ;
} void DFS(int u,int fa)
{
++Time;
int deep = Time;
ola[++ind] = u;
T[Time] = u;
dp[++id] = Time;
in[u] = Time;
for(int i=first[u];i!=-;i=G[i].next)
{
int v = G[i].v;
if(v == fa)
continue;
DFS(v,u);
dp[++id] = deep; //深度序列
ola[++ind] = u; //欧拉序列
}
//if(flag)
//ola[++ind] = u;
out[u] = Time;
} void DFSWG(int u,int w,int fa)
{
dis[u] = w;
for(int i=first[u];i!=-;i=G[i].next)
{
int v = G[i].v;
if(v == fa)
continue;
DFSWG(v,w+G[i].w,u);
}
} void Getpos()
{
memset(vis,,sizeof(vis));
for(int i=;i<=ind;i++)
{
if(!vis[ola[i]])
{
vis[ola[i]] = ;
pos[ola[i]] = i;
}
}
} int LCA(int u,int v)
{
int L = min(pos[u],pos[v]);
int R = max(pos[u],pos[v]);
return T[RMQ(L,R)];
} int lowbit(int x)
{
return x&(-x);
} void update(int k,int num)
{
while(k <= n)
{
c[k] += num;
k += lowbit(k);
}
} int query(int k)
{
int sum = ;
while(k > )
{
sum += c[k];
k -= lowbit(k);
}
return sum;
} int main()
{
int i,j,u,v,w,op,q;
scanf("%d",&n);
{
init();
for(i=;i<n-;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
scanf("%d",&q);
DFS(,-);
Getpos();
RMQ_init();
DFSWG(,,-); //算出dis
while(q--)
{
scanf("%d%d%d",&op,&u,&v);
if(op == )
{
int lca = LCA(u,v);
printf("%d\n",dis[u]+dis[v]-*dis[lca]+query(in[u])+query(in[v])-*query(in[lca]));
}
else
{
int s = G[*u-].u;
int t = G[*u-].v;
if(pos[s] > pos[t]) //保证s是t的父亲
swap(s,t);
int delta = v - G[*u-].w;
G[*u-].w = G[*u].w = v; //更新权值
update(in[t],delta);
update(out[t]+,-delta);
}
}
}
return ;
}

UESTC 912 树上的距离 --LCA+RMQ+树状数组的更多相关文章

  1. POJ 2763 (LCA +RMQ+树状数组 || 树链部分) 查询两点距离+修改边权

    题意: 知道了一颗有  n 个节点的树和树上每条边的权值,对应两种操作: 0 x        输出 当前节点到 x节点的最短距离,并移动到 x 节点位置 1 x val   把第 x 条边的权值改为 ...

  2. POJ - 2763 Housewife Wind (树链剖分/ LCA+RMQ+树状数组)

    题意:有一棵树,每条边给定初始权值.一个人从s点出发.支持两种操作:修改一条边的权值:求从当前位置到点u的最短路径. 分析:就是在边可以修改的情况下求树上最短路.如果不带修改的话,用RMQ预处理LCA ...

  3. HDU - 6393 Traffic Network in Numazu (LCA+RMQ+树状数组)

    这道题相当于将这两题结合: http://poj.org/problem?id=2763 http://codeforces.com/gym/101808/problem/K 题意:有N各点N条边的带 ...

  4. HDU6393(LCA + RMQ + 树状数组) n边图,两点最短距离 , 修改边权

    这道题的进阶版本 进阶版本 题意: 一个n个点,n条边的图,2中操作,1是将某条边的权值更改,2是询问两点的最短距离. 题解: 由于n个点,n条边,所以是树加一个环,将环上的边随意取出一条,就是1颗树 ...

  5. Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)

    Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...

  6. hdu5293 lca+dp+树状数组+时间戳

    题意是给了 n 个点的树,会有m条链条 链接两个点,计算出他们没有公共点的最大价值,  公共点时这样计算的只要在他们 lca 这条链上有公共点的就说明他们相交 dp[i]为这个点包含的子树所能得到的最 ...

  7. 【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更 ...

  8. 【BZOJ】1699: [Usaco2007 Jan]Balanced Lineup排队(rmq/树状数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1699 我是用树状数组做的..rmq的st的话我就不敲了.. #include <cstdio& ...

  9. BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )

    全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries ...

随机推荐

  1. Java文件编码自动转换工具类(只改变编码,不会改变文件内容)

    本篇随笔主要介绍了一个用java语言写的将一个文件编码转换为另一个编码并不改变文件内容的工具类: 通过读取源文件内容,用URLEncoding重新编码解码的方式实现. public class Cha ...

  2. css中important的用处

    今天看代码时遇到一段不理解的地方. #note_content { line-height: 22px; border: #DEDEDE 1px solid; background: #FAFAFA; ...

  3. mysql命令行备份数据库

    MySQL数据库使用命令行备份|MySQL数据库备份命令 例如: 数据库地址:127.0.0.1 数据库用户名:root 数据库密码:pass 数据库名称:myweb 备份数据库到D盘跟目录 mysq ...

  4. ILNumerics项目的应用之线性方程

          ILNumerics是一个开源的数值项目,一种NET框架的高性能数学库,它简化了各种数学算法的使用,优化到了C和FORTRAN的速度.现在它提供了一个支持"任何CPU" ...

  5. 【使用 DOM】使用事件

    1. 使用简单事件处理器 可以用几种不同的方式处理事件.最直接的方式是用事件属性创建一个简单事件处理器(simple event handler).元素为它们支持的每一种事件都定义了一个事件属性.举个 ...

  6. SAP Basis常用事务代码

    事务码 描述(中英文)     SBIT Menu 菜单     SBTA Test background processing 后台处理测试     SBTU Background processi ...

  7. How does Web Analytics works under sharePoint 2010

    [http://gokanx.wordpress.com/2013/06/15/how-does-web-analytics-works-under-sharepoint-2010/] You nee ...

  8. 总结隐藏Ribbon菜单的方法

    1. 重载 using (SPSite site = new SPSite("http://SP2010-01")) { using (SPWeb web = site.OpenW ...

  9. SQL 查询学生缺考情况

    有三个表,如果学生缺考,那么在成绩表中就不存在这个学生的这门课程成绩的记录,写一段SQL语句,检索出每个学生缺考的科目.A 学生表(student)字段1 学生号(s_id)字段2 学生名(s_nam ...

  10. swift基础一

    // swift中导入类库使用import,不再使用<>和"" import Foundation // 输出 print("Hello, World!&qu ...