HDU 2586 How far away ?(LCA Tarjan/樹上倍增)
阿新 • • 發佈:2018-12-21
題目:問任意兩個點之間的最短路徑長。
如果用Tarjan做的話,那麼
用LCA算出最近公共祖先lca,長度就是dis[u]+dis[v]-2*dis[lca]
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<queue> #define eps 1e-8 #define memset(a,v) memset(a,v,sizeof(a)) using namespace std; typedef long long int LL; const int MAXL(4*1e4); const int INF(0x7f7f7f7f); const int mod(1e9+7); int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}}; struct node { int to; int next,w; } edge[2*MAXL+50]; int head[2*MAXL+50]; int father[MAXL+50]; int ans[MAXL+50]; int dis[MAXL+50]; bool vis[MAXL+50]; int x[MAXL+50],y[MAXL+50]; struct nodee { int ed,id; } nod; vector<nodee>v[MAXL+50]; int cnt; int Find(int x) { if(x!=father[x]) father[x]=Find(father[x]); return father[x]; } void Join(int x,int y) { int fx=Find(x),fy=Find(y); if(fx!=fy) father[fy]=fx; } void LCA(int u) { vis[u]=true; for(int i=head[u]; ~i; i=edge[i].next) { int v=edge[i].to,w=edge[i].w; if(!vis[v]) { dis[v]=dis[u]+w; LCA(v); Join(u,v); } } for(int i=0; i<v[u].size(); i++) { int ed=v[u][i].ed,id=v[u][i].id; if(vis[ed]==true) { int lca=Find(ed); ans[id]=lca; } } } void add_edge(int x,int y,int w) { edge[cnt].to=y; edge[cnt].next=head[x]; edge[cnt].w=w; head[x]=cnt++; } int n,q; void init() { scanf("%d%d",&n,&q); cnt=0; memset(head,-1); memset(vis,false); memset(ans,0); memset(dis,0); for(int i=0; i<=n; i++) v[i].clear(); for(int i=0; i<=n; i++) father[i]=i; for(int i=1; i<n; i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); add_edge(x,y,w); add_edge(y,x,w); } for(int i=1; i<=q; i++) { scanf("%d%d",x+i,y+i); nod.ed=y[i],nod.id=i; v[x[i]].push_back(nod); nod.ed=x[i],nod.id=i; v[y[i]].push_back(nod); } } int main() { int T; scanf("%d",&T); while(T--) { init(); dis[1]=0; LCA(1); for(int i=1; i<=q; i++) cout<<dis[x[i]]+dis[y[i]]-2*dis[ans[i]]<<endl; } }
樹上倍增
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<queue> #define eps 1e-8 #define swap(a,b) (a=a+b,b=a-b,a=a-b) #define memset(a,v) memset(a,v,sizeof(a)) using namespace std; typedef long long int LL; const int MAXL(4*1e4); const int INF(0x7f7f7f7f); const int mod(1e9+7); int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}}; struct node{ int to,next,w; node(){} node(int to,int next,int w):to(to),next(next),w(w){} }edge[2*MAXL+50]; int head[2*MAXL+50]; int depth[MAXL+50]; int dp[MAXL+50][20]; int dis[MAXL+50][20]; bool vis[MAXL+50]; int n,q,cnt; void init(){ cnt=0; memset(head,-1); memset(dp,0); memset(depth,0); memset(dis,0); memset(vis,false); } void add_edge(int x,int y,int z){ edge[cnt]=node(y,head[x],z); head[x]=cnt++; } void getDepth(int u){ vis[u]=true; for(int i=head[u];~i;i=edge[i].next){ int to=edge[i].to,w=edge[i].w; if(!vis[to]){ depth[to]=depth[u]+1; dis[to][0]=w; dp[to][0]=u; getDepth(to); } } } void getDp(){ for(int up=1;(1<<up)<=n;up++){ for(int i=1;i<=n;i++){ dp[i][up]=dp[dp[i][up-1]][up-1]; dis[i][up]=dis[i][up-1]+dis[dp[i][up-1]][up-1]; } } } int LCA(int x,int y){ int ans=0; if(depth[x]<depth[y]) swap(x,y); int i=-1; while((1<<(i+1))<=depth[x]) i++; for(int j=i;j>=0;j--) if(depth[x]-(1<<j)>=depth[y]) ans+=dis[x][j],x=dp[x][j]; if(x==y) return ans; for(int j=i;j>=0;j--){ if(dp[x][j]!=dp[y][j]){ ans+=dis[x][j]; ans+=dis[y][j]; x=dp[x][j]; y=dp[y][j]; } } return ans+dis[x][0]+dis[y][0]; } int main() { int T; scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&q); for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add_edge(x,y,z); add_edge(y,x,z); } depth[1]=1; getDepth(1); getDp(); while(q--){ int x,y; scanf("%d%d",&x,&y); int ans=LCA(x,y); cout<<ans<<endl; } } }