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. php学习笔记:利用递归实现删除文件目录

    直接删除目录,如果是空目录是可以删除,如果不是空目录,这时候只能先删除目录里面的文件,然后再删除目录.我封装了个删除函数,然后直接调用这个函数.喜欢的可以直接拿去用,编码是gbk的,使用时候注意下编码 ...

  2. winform(MDI窗体容器、权限设置)

    一.MDI窗体容器: 1.功能: 它可以让其它窗体在它的内部打开,无法超出它的范围 将某个窗体的属性:IsMdiContainer设置为true - 窗口样式 2.问题: (1)如何将其它窗体在它的内 ...

  3. 【翻译】Netscaler真实表现性能调整

    源地址:https://msandbu.wordpress.com/2014/10/31/netscaler-and-real-performance-tuning/ 作者显然不是以英语为母语的,所以 ...

  4. JavaScript中的null与nudefined

    null和undefined 概述 null与undefined都可以表示"没有",含义非常相似.将一个变量赋值为undefined或null,老实说,语法效果几乎没区别. var ...

  5. Matlab2014a 提示未找到支持的编译器或 SDK的解决方法

    最近在写论文,用到了matlab版本的libsvm,在混合编译的时候遇到的一点小问题. 我电脑上装的是matlab2014a,window7 64位 >> mbuild -setup 错误 ...

  6. Sharepoint 2013 关于"SPChange"简介

    在SharePoint中,我们经常会需要获取那些改变的项目,其实api为我们提供了SPChange对象,下面,我们通过列表简单介绍下这一对象. 1.创建一个测试列表,名字叫做“SPChangeItem ...

  7. SharePoint 2013 删除母版页报错“This file may not be moved, deleted, renamed, or otherwise edited”

    在使用SharePoint 2013母版页的时候,我复制了一个seattle.master页面,然后想重命名一下发现报错,删除也报错,spd.页面分别试过签入签出以后均报错,错误如下: 尝试找了一下错 ...

  8. SPJS Upload for SharePoint: Custom upload page for uploading documents to various document libraries in a site collection

    http://spjsblog.com/2013/12/08/spjs-upload-for-sharepoint-custom-upload-page-for-uploading-documents ...

  9. Mac下利用(xcode)安装git

    Mac下利用(xcode)安装git 一.AppStore 最安全途径:搜索下载Xcode,(需要AppleID). 其他:直接百度Xcode下载. 二.Xcode 打开Xcode-->Pref ...

  10. Android 文件访问权限的四种模式

    Linux文件的访问权限* 在Android中,每一个应用是一个独立的用户* drwxrwxrwx* 第1位:d表示文件夹,-表示文件* 第2-4位:rwx,表示这个文件的拥有者(创建这个文件的应用) ...