1#树上倍增

  以前写的博客:http://www.cnblogs.com/yyf0309/p/5972701.html

  预处理时间复杂度O(nlog2n),查询O(log2n),也不算难写。

2#st表(RMQ)

  首先对一棵树进行dfs,得到欧拉序列,记录下每个节点的第一次出现位置。

  (先序遍历这棵树,访问到的节点(无论是从深的一层返回还是父节点访问)就加入到序列中,序列长度为2 * n - 1)

  根据欧拉序列神奇的特性,两个点第一次出现的位置之间,深度最小的一个点,是这两个点LCA(反正我是不会证明)。于是可以干什么呢?就建st表就行了。

  预处理时间复杂度O(2nlog2(2n) + n),查询时间复杂度O(log2n)。

codevs 商务旅行:

 /**
* codevs
* Problem#1036
* Accepted
* Time:52ms
* Memory:2736k
*/
#include<iostream>
#include<sstream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<algorithm>
#ifndef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} template<typename T>class Matrix{
public:
T *p;
int lines;
int rows;
Matrix():p(NULL){ }
Matrix(int rows, int lines):lines(lines), rows(rows){
p = new T[(lines * rows)];
}
T* operator [](int pos){
return (p + pos * lines);
}
};
#define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) ///map template starts
typedef class Edge{
public:
int end;
int next;
Edge(const int end = , const int next = ):end(end), next(next){}
}Edge;
typedef class MapManager{
public:
int ce;
int *h;
Edge *edge;
MapManager(){}
MapManager(int points, int limit):ce(){
h = new int[(const int)(points + )];
edge = new Edge[(const int)(limit + )];
memset(h, , sizeof(int) * (points + ));
}
inline void addEdge(int from, int end){
edge[++ce] = Edge(end, h[from]);
h[from] = ce;
}
inline void addDoubleEdge(int from, int end){
addEdge(from, end);
addEdge(end, from);
}
Edge& operator[] (int pos) {
return edge[pos];
}
}MapManager;
#define m_begin(g, i) (g).h[(i)]
///map template ends int n, m;
int cnt = ;
Matrix<int> st;
int* seq;
int *dep, *app;
MapManager g;
const int P = ;
int *mlog2; inline void init() {
readInteger(n);
g = MapManager(n, * n);
seq = new int[(const int)( * n + )];
dep = new int[(const int)(n + )];
app = new int[(const int)(n + )];
for(int i = , a, b; i < n; i++){
readInteger(a);
readInteger(b);
g.addDoubleEdge(a, b);
}
dep[] = ;
} void dfs(int node, int f) {
seq[++cnt] = node;
dep[node] = dep[f] + ;
app[node] = cnt;
for(int i = m_begin(g, node); i != ; i = g[i].next) {
int& e = g[i].end;
if(e == f) continue;
dfs(e, node);
seq[++cnt] = node;
}
} inline void init_log() {
mlog2 = new int[(const int)( * n + )];
mlog2[] = ;
for(int i = ; i <= * n; i++)
mlog2[i] = mlog2[i / ] + ;
} inline void init_st() {
init_log();
st = Matrix<int>(cnt, mlog2[cnt] + );
for(int i = ; i <= cnt; i++)
st[i][] = seq[i];//,cout << i << " " << 0 << ":" << st[i][0] << endl;
for(int j = ; j <= P; j++)
for(int i = ; i + ( << j) - <= cnt; i++)
st[i][j] = (dep[st[i][j - ]] < dep[st[i + ( << (j - ))][j - ]]) ? (st[i][j - ]) : (st[i + ( << (j - ))][j - ]);
// cout << i << " " << j << ":" << st[i][j] << endl;
} inline int lca(int a, int b) {
if(app[a] > app[b]) swap(a, b);
int pos = mlog2[app[b] - app[a] + ];
int u = st[app[a]][pos];
int v = st[app[b] - ( << pos) + ][pos];
return (dep[u] > dep[v]) ? (v) : (u);
} int last;
int dist;
inline void solve() {
readInteger(m);
readInteger(last);
for(int i = , a; i < m; i++){
readInteger(a);
int l = lca(a, last);
dist += dep[a] + dep[last] - * dep[l];
last = a;
}
printf("%d", dist);
} int main() {
init();
dfs(, );
init_st();
solve();
return ;
}

商务旅行(st表)

3#Tarjan算法(离线算法)

  Tarjan需要一个并查集来辅助。

  算法思路大概是这样:

  init:初始化并查集,对查询建一个邻接链表,还是按照存边的方式,要双向的,再用一个数组记录第i个询问是否解决了。

  1.访问子树

  2.每次访问结束后将子树的并查集中的父节点指向当前节点。

  3.子树都访问完了后,开始处理以该节点为起点的询问,如果终点已经被访问过了并且没有被解决,那么这个点和终点的LCA是终点在并查集中的父节点,然后再记录是否解决的那个数组中把对应位置设上true。

  (画画图,还是很容易理解的)

 #include<iostream>
#include<sstream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<algorithm>
#ifndef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} typedef class Edge {
public:
int end;
int next;
int w;
Edge(const int end = , const int next = , const int w = ):end(end), next(next), w(w){ }
}Edge; typedef class MapManager{
public:
int ce;
Edge* edges;
int* h;
MapManager():ce(), edges(NULL), h(NULL){ }
MapManager(int points, int limit):ce(){
edges = new Edge[(const int)(limit + )];
h = new int[(const int)(points + )];
memset(h, , sizeof(int) * (points + ));
}
inline void addEdge(int from, int end, int w){
edges[++ce] = Edge(end, h[from], w);
h[from] = ce;
}
inline void addDoubleEdge(int from, int end, int w){
addEdge(from, end, w);
addEdge(end, from, w);
}
Edge& operator [](int pos){
return edges[pos];
}
}MapManager;
#define m_begin(g, i) (g).h[(i)] typedef class union_found{
public:
int *f;
union_found():f(NULL) {}
union_found(int points) {
f = new int[(const int)(points + )];
}
int find(int x) {
if(f[x] != x) return f[x] = find(f[x]);
return f[x];
}
void unit(int fa, int so) {
int ffa = find(fa);
int fso = find(so);
f[fso] = ffa;
}
int& operator [](int pos){
return f[pos];
}
}union_found; int n, m;
MapManager g;
MapManager q;
int *results;
boolean* enable;
int *querya, *queryb;
union_found uf;
boolean* visited;
int* dist; inline void init(){
readInteger(n);
g = MapManager(n, * n);
for(int i = , a, b, c; i < n; i++){
readInteger(a);
readInteger(b);
readInteger(c);
g.addDoubleEdge(a, b, c);
}
readInteger(m);
q = MapManager(n, * m);
querya = new int[(const int)(m + )];
queryb = new int[(const int)(m + )];
results = new int[(const int)(m + )];
enable = new boolean[(const int)(m + )];
dist = new int[(const int)(n + )];
uf = union_found(n);
visited = new boolean[(const int)(n + )];
memset(visited, false, sizeof(boolean) * (n + ));
memset(enable, true, sizeof(boolean) * (m + ));
for(int i = ; i <= m; i++){
readInteger(querya[i]);
readInteger(queryb[i]);
q.addDoubleEdge(querya[i], queryb[i], i);
}
dist[] = ;
} void tarjan(int node, int f){
uf[node] = node;
visited[node] = true;
for(int i = m_begin(g, node); i != ; i = g[i].next){
int& e = g[i].end;
if(e == f) continue;
dist[e] = dist[node] + g[i].w;
tarjan(e, node);
uf[e] = node;
}
for(int i = m_begin(q, node); i != ; i = q[i].next) {
int& e = q[i].end;
if(visited[e] && enable[q[i].w]){
int lca = uf.find(e);
results[q[i].w] = lca;
enable[q[i].w] = false;
}
}
} inline void solve(){
tarjan(, );
for(int i = ; i <= m; i++){
int dis = dist[querya[i]] + dist[queryb[i]] - * dist[results[i]];
printf("%d\n", dis);
}
} int main(){
init();
solve();
return ;
}

Tajan

4#树链剖分

  详见:http://www.cnblogs.com/yyf0309/p/6344982.html

  树链剖分的空间复杂度比上面任何一种方法都要优,所以当空间很紧的时候(当然,我相信出题人不会那么坑人)是不错的选择。

[算法整理]树上求LCA算法合集的更多相关文章

  1. 倍增求LCA算法详解

    算法介绍: 看到lca问题(不知道lca是什么自(bang)行(ni)百度),不难想到暴力的方法: 先把两点处理到同一深度,再让两点一个一个祖先往上找,直到找到一个相同的祖先: 这么暴力的话,时间复杂 ...

  2. [算法模板]倍增求LCA

    倍增LCA \(fa[a][i]\)代表a的第\(2^{i}\)个祖先. 主体思路是枚举二进制位,让两个查询节点跳到同一高度然后再向上跳相同高度找LCA. int fa[N][21], dep[N]; ...

  3. Misha, Grisha and Underground CodeForces - 832D (倍增树上求LCA)

    Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations ...

  4. 模板 树上求LCA 倍增和树链剖分

    //233 模板 LCA void dfs(int x,int f){ for(int i=0;i<E[x].size();i++){ int v = E[x][i]; if(v==f)cont ...

  5. [学习笔记] 树上倍增求LCA

    倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. ...

  6. WooCommerce代码合集整理

    本文整理了一些WooCommerce代码合集,方便查阅和使用,更是为了理清思路,提高自己.以下WooCommerce简称WC,代码放在主题的functions.php中即可. 修改首页和分类页面每页产 ...

  7. Tarjan求LCA

    LCA问题算是一类比较经典的树上的问题 做法比较多样 比如说暴力啊,倍增啊等等 今天在这里给大家讲一下tarjan算法! tarjan求LCA是一种稳定高速的算法 时间复杂度能做到预处理O(n + m ...

  8. 倍增 Tarjan 求LCA

                                                                                                         ...

  9. 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

    [题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...

随机推荐

  1. ArcEngine创建要素类_线类型

    public ESRI.ArcGIS.Geodatabase.IFeatureClass CreateFeatureClassForLine(ESRI.ArcGIS.Geodatabase.IWork ...

  2. Reading table information for completion of table and column names

    mysql> use ad_detail_page;Reading table information for completion of table and column namesYou c ...

  3. Map集合遍历

    Map<String,String> map = new HashMap<String, String>(); map.put("1","java ...

  4. 【python-opencv】15-图像阈值

    [微语]立志要如山,行道要如水.不如山,不能坚定,不如水,不能曲达 import cv2 as cv import numpy as np from matplotlib import pyplot ...

  5. 几种outofmemory

    几种outofmemory的解决方法:1.  java.lang.OutOfMemoryError: PermGen space PermGen space的全称是Permanent Generati ...

  6. 【查阅】mysql系统视图查看

    [1]查看表大小 SELECT CONCAT(table_schema,'.',table_name) AS 'Table Name', table_rows AS 'Number of Rows', ...

  7. Build-in Function:abs(),all(),any(),assii(),bin(),issubclass(),bytearray(),isinstance()

    print('abs():输出绝对值,是absolute的缩写--------------') print(abs(-1)) print('all()与any()------------------- ...

  8. CentOS6.5安装Twemproxy集群

    Twemproxy,也叫Nutcraker.是一个Twtter开源的一个Redis和Memcache代理服务器. Redis作为一个高效的缓存服务器,非常具有应用价值.但是当使用比较多的时候,就希望可 ...

  9. 机器学习理论基础学习14.1---线性动态系统-卡曼滤波 Kalman filter

    一.背景 动态模型 = 图 + 时间 动态模型有三种:HMM.线性动态系统(kalman filter).particle filter 线性动态系统与HMM的区别是假设相邻隐变量之间满足线性高斯分布 ...

  10. smali过滤特定字符串

    过滤插入代码: const-string/jumbo v0, "aaaaaaa" invoke-static {v0}, Lcom/bihu/insurancerobot/util ...