[HDU2586] How far away ?{LCA.tarjan演算法/倍增演算法}
阿新 • • 發佈:2018-12-08
文章目錄
題目
http://acm.hdu.edu.cn/showproblem.php?pid=2586
解題思路
倍增演算法
LCA.tarjan演算法
這個 不是縮點的
注意:倍增是線上演算法,tarjan是離線演算法
程式碼倍增(TLE)
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<string>
#define rr register
using namespace std;
const int size=40010;
int f[size][20],d[size],dist[size];
int ver[size>>1],nex[size>>1],edge[size>>1],head[size];
int T,n,m,tot,t;
queue<int> q;
void add(int x,int y,int z)
{ ver[++tot]=y; edge[tot]=z; nex[tot]=head[x]; head[x]=tot; }
inline int read()
{
int p=0,b=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') b=-1; c=getchar();}
while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar();
return p*b;
}
void write(int x){if (x>9) write(x/10); putchar(x%10+48);}
void bfs(){
q.push(1); d[1]=1;
while (q.size()){
int x=q.front(); q.pop();
for (rr int i=head[x];i;i=nex[i]){
int y=ver[i];
if (d[y]) continue;
d[y]=d[x]+1; dist[y]=dist[x]+edge[i]; f[y][0]=x;
for (int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1];
q.push(y);
}
}
}
inline int lca(int x,int y)
{
if (d[x]>d[y]) swap(x,y);
for (rr int i=t;i>=0;i--)
if (d[f[y][i]]>=d[x]) y=f[y][i];
if (x==y) return x;
for (rr int i=t;i>=0;i--)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
T=read();
while (T--){
n=read(),m=read();
t=(int)log2(n)+1; tot=0;
for (rr int i=1;i<=n;i++) head[i]=d[i]=dist[i]=0;
for (rr int i=1;i<n;i++)
{
int x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
bfs();
for (rr int i=1;i<=m;putchar('\n'),i++)
{int x=read(),y=read(); write(dist[x]+dist[y]-2*dist[lca(x,y)]);}
}
return 0;
}
程式碼tarjan演算法(AC)
演算法本質上是使用並查集對“向上標記法”的優化
#include<vector>
#include<cstdio>
#define Size 50010
using namespace std;
int ver[Size*2],Next[Size*2],edge[Size*2],head[Size];
int fa[Size],d[Size],v[Size],lca[Size],ans[Size];
vector<int> query[Size],query_id[Size];
int T,n,m,tot,t;
void addd(int x,int y,int z){
ver[++tot]=y; edge[tot]=z; Next[tot]=head[x]; head[x]=tot;
}
void add_query(int x,int y,int id){
query[x].push_back(y),query_id[x].push_back(id);
query[y].push_back(x),query_id[y].push_back(id);
}
int get(int x){return (x==fa[x])?x:fa[x]=get(fa[x]);}
void tarjan(int x){
v[x]=1;
for (int i=head[x];i;i=Next[i]){
int y=ver[i];
if (v[y]) continue;
d[y]=d[x]+edge[i];
tarjan(y);
fa[y]=x;
}
for (int i=0;i<query[x].size();i++){
int y=query[x][i],id=query_id[x][i];
if (v[y]==2){
int lca=get(y);
ans[id]=min(ans[id],d[x]+d[y]-2*d[lca]);
}
}
v[x]=2;
}
int main()
{
scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
head[i]=0; fa[i]=i; v[i]=0; query[i].clear(),query_id[i].clear();
}
tot=0;
for (int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addd(x,y,z),addd(y,x,z);
}
for (int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
if (x==y) ans[i]=0;
else {
add_query(x,y,i);
ans[i]=1<<30;
}
}
tarjan(1);
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
}