LCA的三种求法 - HDU 2586
2017-10-30 17:37
204 查看
Tarjan
一遍 大法师 处理所有询问, 每次递归处理子树, 把子树与当前节点的并查集合并. 然后如果一个询问的两个节点都被访问, 直接输出答案
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
int T,n,m,a,b,c,p[40010],vis[40010],dep[40010],ans[210];
vector<pair<int,int> >g[40010];
vector<pair<int,int> >ask[40010];
int find(int x) {
return x==p[x]?x:p[x]=find(p[x]);
}
void Tarjan(int u,int fa,int d) {
dep[u]=d;
for(int i=0;i<g[u].size();i++) {
pair<int,int> &v=g[u][i];
if(v.first!=fa) {
Tarjan(v.first,u,d+v.second);
p[v.first]=find(u);
}
}
vis[u]=1;
for(int i=0;i<ask[u].size();i++) {
pair<int,int> &v=ask[u][i];
if(vis[v.first]) {
ans[v.second]=dep[u]+dep[v.first]-2*dep[find(v.first)];
}
}
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
memset(vis,0,sizeof vis);
memset(ans,-1,sizeof ans);
for(int i=0;i<=n;i++) {
g[i].clear();
ask[i].clear();
}
for(int i=1;i<n;i++) {
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
}
for(int i=1;i<=m;i++) {
scanf("%d%d",&a,&b);
ask[a].push_back(make_pair(b,i));
ask[b].push_back(make_pair(a,i));
}
for(int i=1;i<=n;i++) p[i]=i;
Tarjan(1,0,0);
for(int i=1;i<=m;i++) {
printf("%d\n",ans[i]);
}
}
}
`RMQ 求法 (ST 表)
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int T,n,m,a,b,c,time,e[80010],p[40010],dep[40010],dp[22][80010];
vector<pair<int,int> >g[40010];
void dfs(int u,int fa,int d) {
dep[u]=d;
p[u]=time;
e[time++]=u;
for(int i=0;i<g[u].size();i++) {
if(g[u][i].first!=fa) {
dfs(g[u][i].first,u,d+g[u][i].second);
e[time++]=u;
}
}
}
void rmq() {
for(int i=1;i<2*n;i++) dp[0][i]=e[i];
for(int i=1;1<<i<=2*n;i++) {
for(int j=1;j<2*n;j++) {
dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i-1)]);
}
}
}
int getmin(int l,int r) {
if(l>r) swap(l,r);
int i=0;
while((1<<i)<=r-l+1) i++; i--;
return min(dp[i][l],dp[i][r-(1<<i)+1]);
}
int main() {
scanf("%d",&T);
while(T--) {
time=1;
memset(e,0,sizeof e);
memset(p,0,sizeof p);
memset(dp,63,sizeof dp);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<n;i++) {
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
}
dfs(1,-1,0);
rmq();
while(m--) {
scanf("%d%d",&a,&b);
c=getmin(p[a],p[b]);
printf("%d\n",dep[a]+dep[b]-2*dep[c]);
}
}
}
倍增
写挂了
一遍 大法师 处理所有询问, 每次递归处理子树, 把子树与当前节点的并查集合并. 然后如果一个询问的两个节点都被访问, 直接输出答案
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
int T,n,m,a,b,c,p[40010],vis[40010],dep[40010],ans[210];
vector<pair<int,int> >g[40010];
vector<pair<int,int> >ask[40010];
int find(int x) {
return x==p[x]?x:p[x]=find(p[x]);
}
void Tarjan(int u,int fa,int d) {
dep[u]=d;
for(int i=0;i<g[u].size();i++) {
pair<int,int> &v=g[u][i];
if(v.first!=fa) {
Tarjan(v.first,u,d+v.second);
p[v.first]=find(u);
}
}
vis[u]=1;
for(int i=0;i<ask[u].size();i++) {
pair<int,int> &v=ask[u][i];
if(vis[v.first]) {
ans[v.second]=dep[u]+dep[v.first]-2*dep[find(v.first)];
}
}
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
memset(vis,0,sizeof vis);
memset(ans,-1,sizeof ans);
for(int i=0;i<=n;i++) {
g[i].clear();
ask[i].clear();
}
for(int i=1;i<n;i++) {
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
}
for(int i=1;i<=m;i++) {
scanf("%d%d",&a,&b);
ask[a].push_back(make_pair(b,i));
ask[b].push_back(make_pair(a,i));
}
for(int i=1;i<=n;i++) p[i]=i;
Tarjan(1,0,0);
for(int i=1;i<=m;i++) {
printf("%d\n",ans[i]);
}
}
}
`RMQ 求法 (ST 表)
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int T,n,m,a,b,c,time,e[80010],p[40010],dep[40010],dp[22][80010];
vector<pair<int,int> >g[40010];
void dfs(int u,int fa,int d) {
dep[u]=d;
p[u]=time;
e[time++]=u;
for(int i=0;i<g[u].size();i++) {
if(g[u][i].first!=fa) {
dfs(g[u][i].first,u,d+g[u][i].second);
e[time++]=u;
}
}
}
void rmq() {
for(int i=1;i<2*n;i++) dp[0][i]=e[i];
for(int i=1;1<<i<=2*n;i++) {
for(int j=1;j<2*n;j++) {
dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i-1)]);
}
}
}
int getmin(int l,int r) {
if(l>r) swap(l,r);
int i=0;
while((1<<i)<=r-l+1) i++; i--;
return min(dp[i][l],dp[i][r-(1<<i)+1]);
}
int main() {
scanf("%d",&T);
while(T--) {
time=1;
memset(e,0,sizeof e);
memset(p,0,sizeof p);
memset(dp,63,sizeof dp);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<n;i++) {
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(make_pair(b,c));
g[b].push_back(make_pair(a,c));
}
dfs(1,-1,0);
rmq();
while(m--) {
scanf("%d%d",&a,&b);
c=getmin(p[a],p[b]);
printf("%d\n",dep[a]+dep[b]-2*dep[c]);
}
}
}
倍增
写挂了
相关文章推荐
- HDU - 2586 How far away ?(tarjan离线做法求lca)
- hdu 2586(最近公共祖先LCA)
- HDU 2586 How far away ? 离线LCA
- hdu-2586 How far away ?(lca+bfs+dfs+线段树)
- 最近公共祖先(lca) hdu 2586
- hdu 2586 How far away ? (LCA)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- How far away ? HDU - 2586 tarjan求LCA
- hdu--2586--lca_tarjan<证明tarjan这个人很流弊>
- LCA最近公共祖先 hdu-2586
- HDU2586 How far away ?(最近公共祖先lca,离线Tarjan,最短路)
- hdu 2586 最近公共祖先 LCA
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- HDU-2586-How far away ?(倍增求LCA模板)
- HDU 2586 How far away ? LCA离线tarjan思想
- HDU 2586 How far away ? (LCA模板题 Tarjan算法求最小公共祖先)
- 【Lca 在线st算法】hdu 2586 How far away ?
- HDU 2586 How far away? LCA 离线tarjan
- hdu 2586 How far away ? 带权lca
- [hdu 2586]lca模板题(在线+离线两种版本)