您的位置:首页 > 其它

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]);
}
}
}

倍增
写挂了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: