题目链接~~>

做题感悟:这题開始看到时感觉不是树不优点理,一想能够用 Kruskal 处理成树 ,然后就好攻克了。

解题思路:

先用 Kruskal 处理出最小生成树。然后用树链剖分 + 线段树处理就能够了。

代码:

#include<iostream>
#include<sstream>
#include<map>
#include<cmath>
#include<fstream>
#include<queue>
#include<vector>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<bitset>
#include<ctime>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std ;
#define INT long long int
#define L(x) (x * 2)
#define R(x) (x * 2 + 1)
const int INF = 0x3f3f3f3f ;
const double esp = 0.0000000001 ;
const double PI = acos(-1.0) ;
const int mod = 1000000007 ;
const int MY = (1<<5) + 5 ;
const int MX = 100000 + 5 ;
int n ,m ,nx ,idx ,num ;
int head[MX] ,ti[MX] ,siz[MX] ,son[MX] ,father[MX] ,top[MX] ,dep[MX] ;
struct NODE
{
int u ,v ,w ;
}e[MX] ;
struct MNODE
{
int u ,v ,w ;
}t[MX] ;
struct Edge
{
int u ,v ,w ,next ;
}E[MX*2] ;
void addedge(int u ,int v ,int w)
{
E[num].v = v ; E[num].w = w ; E[num].next = head[u] ; head[u] = num++ ;
E[num].v = u ; E[num].w = w ; E[num].next = head[v] ; head[v] = num++ ;
}
bool cmp(NODE a ,NODE b)
{
return a.w < b.w ;
}
int find(int u)
{
if(father[u] != u)
return find(father[u]) ;
else return u ;
}
void Kruskal()
{
nx = 1 ;
int u ,v ,fa ,fb ;
sort(e ,e+m ,cmp) ;
for(int i = 0 ;i <= n ; ++i)
father[i] = i ;
for(int i = 0 ;i < m ; ++i)
{
u = e[i].u ; v = e[i].v ;
fa = find(u) ;
fb = find(v) ;
if(fa != fb)
{
father[fa] = fb ;
addedge(u ,v ,e[i].w) ;
t[nx].u = u ; t[nx].v = v ; t[nx++].w = e[i].w ;
}
}
}
void dfs_find(int u ,int fa)
{
dep[u] = dep[fa] + 1 ;
father[u] = fa ;
siz[u] = 1 ;
son[u] = 0 ;
for(int i = head[u] ;i != -1 ;i = E[i].next)
{
int v = E[i].v ;
if(v == fa) continue ;
dfs_find(v ,u) ;
siz[u] += siz[v] ;
if(siz[son[u]] < siz[v]) son[u] = v ;
}
}
void dfs_time(int u ,int fa)
{
top[u] = fa ;
ti[u] = idx++ ;
if(son[u]) dfs_time(son[u] ,top[u]) ;
for(int i = head[u] ;i != -1 ;i = E[i].next)
{
int v = E[i].v ;
if(v == father[u] || v == son[u]) continue ;
dfs_time(v ,v) ;
}
}
struct node
{
int le ,rt ,c ;
}T[MX*4] ;
void build(int i ,int le ,int rt)
{
T[i].le = le ; T[i].rt = rt ;
T[i].c = 0 ;
if(le == rt) return ;
int Mid = (le + rt)>>1 ;
build(L(i) ,le ,Mid) ;
build(R(i) ,Mid+1 ,rt) ;
}
void update(int i ,int pos ,int w)
{
if(T[i].le == T[i].rt)
{
T[i].c = w ;
return ;
}
int Mid = (T[i].le + T[i].rt)>>1 ;
if(pos <= Mid) update(L(i) ,pos ,w) ;
else update(R(i) ,pos ,w) ;
T[i].c = max(T[L(i)].c ,T[R(i)].c) ;
}
int section(int i ,int le ,int rt)
{
if(T[i].le == le && T[i].rt == rt)
return T[i].c ;
int Mid = (T[i].le + T[i].rt)>>1 ;
if(le > Mid) return section(R(i) ,le ,rt) ;
else if(rt <= Mid) return section(L(i) ,le ,rt) ;
else
return max(section(L(i) ,le ,Mid) ,section(R(i) ,Mid+1 ,rt)) ;
}
int LCA(int u ,int v)
{
int ans = 0 ;
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]])
swap(u ,v) ;
ans = max(ans ,section(1 ,ti[top[u]] ,ti[u])) ;
u = father[top[u]] ;
}
if(dep[u] > dep[v]) swap(u ,v) ;
if(u != v)
ans = max(ans ,section(1 ,ti[u]+1 ,ti[v])) ;
return ans ;
}
int main()
{
int u ,v ,Q ;
bool first = false ;
while(~scanf("%d%d" ,&n ,&m))
{
if(first) puts("") ;
first = true ;
num = 0 ;
memset(head ,-1 ,sizeof(head)) ;
for(int i = 0 ;i < m ; ++i)
scanf("%d%d%d" ,&e[i].u ,&e[i].v ,&e[i].w) ;
Kruskal() ;
dep[1] = siz[0] = 0 ;
dfs_find(1 ,1) ;
idx = 1 ;
dfs_time(1 ,1) ;
build(1 ,1 ,n) ;
for(int i = 1 ;i < nx ; ++i)
{
if(dep[t[i].u] < dep[t[i].v])
swap(t[i].u ,t[i].v) ;
update(1 ,ti[t[i].u] ,t[i].w) ;
}
scanf("%d" ,&Q) ;
for(int i = 0 ;i < Q ; ++i)
{
scanf("%d%d" ,&u ,&v) ;
printf("%d\n" ,LCA(u ,v)) ;
}
}
return 0 ;
}

倍增法 (类似RMQ)

代码:

#include<iostream>
#include<sstream>
#include<map>
#include<cmath>
#include<fstream>
#include<queue>
#include<vector>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<bitset>
#include<ctime>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std ;
#define INT long long int
#define L(x) (x * 2)
#define R(x) (x * 2 + 1)
const int INF = 0x3f3f3f3f ;
const double esp = 0.0000000001 ;
const double PI = acos(-1.0) ;
const int mod = 1000000007 ;
const int MY = (1<<5) + 5 ;
const int MX = 100000 + 5 ;
const int S = 20 ;
int n ,m ,idx ,num ,nx ;
int value[MX][25] ,p[MX][25] ,ti[MX] ,father[MX] ,dep[MX] ,head[MX] ;
struct TEMP
{
int u ,v ,w ;
}A[MX] ;
struct Edge
{
int v ,w ,next ;
}E[MX*2] ;
bool cmp(TEMP a ,TEMP b)
{
return a.w < b.w ;
}
int find(int u)
{
if(father[u] != u)
return find(father[u]) ;
return u ;
}
void addedge(int u ,int v ,int w)
{
E[num].v = v ; E[num].w = w ; E[num].next = head[u] ; head[u] = num++ ;
E[num].v = u ; E[num].w = w ; E[num].next = head[v] ; head[v] = num++ ;
}
void Kruskal()
{
nx = 1 ;
int fa ,fb ;
sort(A ,A+m ,cmp) ;
for(int i = 0 ;i <= n ; ++i)
father[i] = i ;
for(int i = 0 ;i < m ; ++i)
{
fa = find(A[i].u) ;
fb = find(A[i].v) ;
if(fa != fb)
{
father[fa] = fb ;
addedge(A[i].u ,A[i].v ,A[i].w) ;
}
}
}
void dfs_find(int u ,int fa ,int w)
{
dep[u] = dep[fa] + 1 ;
p[u][0] = fa ;
value[u][0] = w ;
for(int i = 1 ;i <= S ; ++i)
{
p[u][i] = p[p[u][i-1]][i-1] ;
value[u][i] = max(value[u][i-1] ,value[p[u][i-1]][i-1]) ;
}
for(int i = head[u] ;i != -1 ;i = E[i].next)
{
int v = E[i].v ;
if(v == fa) continue ;
dfs_find(v ,u ,E[i].w) ;
}
}
int LCA(int u ,int v)
{
int ans = 0 ;
if(dep[u] > dep[v]) swap(u ,v) ;
if(dep[u] < dep[v])
{
int d = dep[v] - dep[u] ;
for(int i = 0 ;i <= S ; ++i)
if(d&(1<<i))
{
ans = max(ans ,value[v][i]) ;
v = p[v][i] ;
}
}
if(u != v)
{
for(int i = S ;i >= 0 ; --i)
if(p[u][i] != p[v][i])
{
ans = max(ans ,value[u][i]) ;
ans = max(ans ,value[v][i]) ;
u = p[u][i] ;
v = p[v][i] ;
}
ans = max(ans ,value[u][0]) ;
ans = max(ans ,value[v][0]) ;
}
return ans ;
}
void init()
{
num = 0 ;
memset(head ,-1 ,sizeof(head)) ;
memset(ti ,0 ,sizeof(ti)) ;
memset(value ,0 ,sizeof(value)) ;
memset(p ,0 ,sizeof(p)) ;
memset(dep ,0 ,sizeof(dep)) ;
}
int main()
{
//freopen("input.txt" ,"r" ,stdin) ;
int u ,v ,Q ;
bool first = false ;
while(~scanf("%d%d" ,&n ,&m))
{
if(first) puts("") ;
first = true ;
init() ;
for(int i = 0 ;i < m ; ++i)
scanf("%d%d%d" ,&A[i].u ,&A[i].v ,&A[i].w) ;
Kruskal() ;
dep[1] = 0 ;
dfs_find(1 ,1 ,0) ;
scanf("%d" ,&Q) ;
while(Q--)
{
scanf("%d%d" ,&u ,&v) ;
printf("%d\n" ,LCA(u ,v)) ;
}
}
return 0 ;
}

UVA 11354 - Bond (最小生成树 + 树链剖分)的更多相关文章

  1. 【bzoj2238】Mst 最小生成树+树链剖分+线段树

    题目描述 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在) 输入 第一行两 ...

  2. [wikioi 1519]过路费(最小生成树+树链剖分)

    题目:http://www.wikioi.com/problem/1519/ 题意:给你一个连通的无向图,每条边都有权值,给你若干个询问(x,y),要输出从x到y的路径上边的最大值的最小值 分析:首先 ...

  3. Educational Codeforces Round 3 E. Minimum spanning tree for each edge (最小生成树+树链剖分)

    题目链接:http://codeforces.com/contest/609/problem/E 给你n个点,m条边. 问枚举每条边,问你加这条边的前提下组成生成树的权值最小的树的权值和是多少. 先求 ...

  4. Educational Codeforces Round 3 E. Minimum spanning tree for each edge 最小生成树+树链剖分+线段树

    E. Minimum spanning tree for each edge time limit per test 2 seconds memory limit per test 256 megab ...

  5. HDU3710 Battle over Cities(最小生成树+树链剖分+倍增+线段树)

    Battle over Cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  6. [BZOJ2238]Mst 最小生成树+树链剖分/并查集

    链接 题解 先构建出最小生成树,如果删的是非树边,直接输出答案 否则问题转化为,把该边删掉后剩下两个联通块,两个端点分别在两个块内的最小边权,LCT可以维护 不妨换一种思考方向:考虑一条非树边可以代替 ...

  7. UVA 11354 Bond 最小生成树 + lca

    题意 给出一张图,q个询问,每次询问给出uv,找出一条路径,使这条路径上的最大边权是两点所有路径中最小,输出这个值 思路 很显然要先求出最小生成树,任意两点在最小生成树上有唯一路径,并且这条路径上的最 ...

  8. uva 11354 - Bond(树链拆分)

    题目链接:uva 11354 - Bond 题目大意:给定一张图.每次询问两个节点路径上进过边的危急值的最大值的最小值. 解题思路:首先建立最小生成数,然后依据这棵树做树链剖分. #include & ...

  9. 严格次小生成树[BJWC2010] (树链剖分,倍增,最小生成树)

    题目链接 Solution 有几点关键,首先,可以证明次小生成树一定是由最小生成树改变一条边而转化来. 所以需要枚举所有非最小生成树的边\((u,v)\).并且找到 \(u\) 到 \(v\) 的边中 ...

随机推荐

  1. Ubuntu 14.04LTS+Git

    Git是我们常用的代码托管工具,作为程序员,Git是必备的. 安装Git的方法很简单,官网就有写:http://git-scm.com/download/linux 根据官网的说明,用: sudo a ...

  2. IDEA 提交项目至Git与获取Git项目

    1.IDEA提交项目至git 注:保证已安装Git分布式管理系统,没有自行百度安装git 1)在IDEA中配置Git与GitHub a)Git: File-->Settings --> V ...

  3. POJ 2761 Feed the dogs (主席树)(K-th 值)

                                                                Feed the dogs Time Limit: 6000MS   Memor ...

  4. 洛谷五月月赛 T1

    做一下差分之后,把每个位置的差分数看成这个位置有多少个石子,于是每次操作就是选一个有石子的位置并把这个位置的石子移到后面的位置(如果这个位置已经是最后了那么直接扔掉). 所以就是带权石子问题了,最后判 ...

  5. POJ 2155 Matrix(树状数组+容斥原理)

    [题目链接] http://poj.org/problem?id=2155 [题目大意] 要求维护两个操作,矩阵翻转和单点查询 [题解] 树状数组可以处理前缀和问题,前缀之间进行容斥即可得到答案. [ ...

  6. linux之rpm指令

    rmp原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采用.RPM套件管理方式的出现,让Linux易于 ...

  7. linux之vim命令

    :tabe fn     在一个新的标签页中编辑文件fngt     切换到下一个标签页gT     切换到上一个标签页:tabr     切换到第一个标签页:tabl     切换到最后一个标签页: ...

  8. 阿里云域名绑定IP

    前提条件:拥有一个阿里云域名,拥有一台自己的服务器,并且知道ip,我的是nginx 1.登陆阿里云https://www.aliyun.com/ 2.选择域名与网站,会看到自己拥有的域名,比如我的是m ...

  9. .net开发常用的第三方开发组件

    转自:http://www.cnblogs.com/damsoft/p/6100323.html .net开发常用的第三方组件: 1.RSS.NET.dll: RSS.NET是一款操作RSS feed ...

  10. 13 Basic Cat Command Examples in Linux

    FROM: http://www.tecmint.com/13-basic-cat-command-examples-in-linux/ The cat (short for “concatenate ...