UESTC 912 树上的距离 --LCA+RMQ+树状数组
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+树状数组的更多相关文章
- POJ 2763 (LCA +RMQ+树状数组 || 树链部分) 查询两点距离+修改边权
题意: 知道了一颗有 n 个节点的树和树上每条边的权值,对应两种操作: 0 x 输出 当前节点到 x节点的最短距离,并移动到 x 节点位置 1 x val 把第 x 条边的权值改为 ...
- POJ - 2763 Housewife Wind (树链剖分/ LCA+RMQ+树状数组)
题意:有一棵树,每条边给定初始权值.一个人从s点出发.支持两种操作:修改一条边的权值:求从当前位置到点u的最短路径. 分析:就是在边可以修改的情况下求树上最短路.如果不带修改的话,用RMQ预处理LCA ...
- HDU - 6393 Traffic Network in Numazu (LCA+RMQ+树状数组)
这道题相当于将这两题结合: http://poj.org/problem?id=2763 http://codeforces.com/gym/101808/problem/K 题意:有N各点N条边的带 ...
- HDU6393(LCA + RMQ + 树状数组) n边图,两点最短距离 , 修改边权
这道题的进阶版本 进阶版本 题意: 一个n个点,n条边的图,2中操作,1是将某条边的权值更改,2是询问两点的最短距离. 题解: 由于n个点,n条边,所以是树加一个环,将环上的边随意取出一条,就是1颗树 ...
- Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...
- hdu5293 lca+dp+树状数组+时间戳
题意是给了 n 个点的树,会有m条链条 链接两个点,计算出他们没有公共点的最大价值, 公共点时这样计算的只要在他们 lca 这条链上有公共点的就说明他们相交 dp[i]为这个点包含的子树所能得到的最 ...
- 【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)
http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更 ...
- 【BZOJ】1699: [Usaco2007 Jan]Balanced Lineup排队(rmq/树状数组)
http://www.lydsy.com/JudgeOnline/problem.php?id=1699 我是用树状数组做的..rmq的st的话我就不敲了.. #include <cstdio& ...
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )
全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries ...
随机推荐
- Java的集合框架
01.为什么要使用集合框架? 解析:如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象,那么可以使用Java集合框架. 如果启用集合的删除方法,那么集合中所有元素的索引会自动维护. 集合 ...
- maven nexus deploy方式以及相关注意事项
以前公司都是配管负责管理jar的,现在没有专职配管了,得自己部署到deploy上供使用.总的来说,jar部署到nexus上有两种方式: 1.直接登录nexus控制台进行上传,如下: 但是,某些仓库可能 ...
- Android笔记——Android中数据的存储方式(二)
我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...
- Android SDK Tools和Android SDK Platform-tools
SDK Platform 可以理解为版本,因此有 SDK Platform 7,SDK Platform 8等等Android SDK Tools 是各个版本都可通用的工具文件夹,里面有draw9pa ...
- Linux 学习手记(4):Linux系统常用Shell命令
日期时间 date命令:显示当前时间日期 date -u # 显示格林威治(UTC)事件 date +%Y-%m-%d # 格式显示日期 date -s '20:25:25' # 修改系统时间,需要使 ...
- SeismicPro地震剖面显示程序
SeismicPro是一个地震剖面显示软件,可从标准SEGY地震数据体中抽取纵测线和横测线的二维剖面,并以波形.变面积和变密度等多种方式进行专业化显示,可进行一键式显示方式切换,并可进行定制开发叠加井 ...
- 深入理解java虚拟机(3)---类的结构
计算机在开始的时候,只认识0和1,所以汇编语言是和机器结构或者说CPU绑定的.ARM体系结构就是这样一种体现,指令集的概念. 随着高级语言的出现,从字编码发展到了字节编码,计算机的先驱希望能够让语言能 ...
- 推些C语言与算法书籍
c语言系统学习与进阶: 1. C primer plus C primer plus 作为一本被人推崇备至的 c 入门经典,C primer plus 绝非浪得虚名.应该 算得上 C 教材里最好的入门 ...
- android多种布局的列表实现
最近有一个列表效果,需要一个列表有多种布局,最终效果如下: 这个我也问了同事以及开发群里的朋友,居然都没得到最优的实现方式的回答,看来这种复杂列表的需求还是比较少的,我自己也走了一些弯路,把我几个实现 ...
- 每日Scrum--No.4
Yesterday:学习迪杰斯特拉算法并进行简单的编写代码 Today:继续编写代码 Problem:变量名的定义出错,造成调用的时候出错,不过改过来就好了.算法的编写不全面,漏掉个别语句,如在调试的 ...