How far away: RMQ 與 LCA
阿新 • • 發佈:2018-11-06
題目連結:How far away
http://acm.hdu.edu.cn/showproblem.php?pid=2586
RMQ做法
這裡滿足一個性質:對於任意的x,y,他們的lca必定是x,y的路徑上的最淺的點(dep最小)
所以我們就可以記錄路徑(注意將路徑上的數放在一個連續區間裡),然後用倍增就可以找到某一區間的Min值啦
程式碼在這裡:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=40005; int n,m,cnt,iindex; int u[maxn*2],v[maxn*2],w[maxn*2],log2[maxn]; int nxt[maxn*2],head[maxn],dep[maxn]; int vis[maxn*2],f[maxn*2][33],pos[maxn]; void init() { cnt=0;iindex=0; memset(head,-1,sizeof(head)); memset(f,0,sizeof(f)); memset(dep,0,sizeof(dep)); memset(pos,0,sizeof(pos)); } void add_edge(int x,int y,int z) { cnt++;u[cnt]=x;v[cnt]=y;w[cnt]=z; nxt[cnt]=head[x];head[x]=cnt; } void find(int x,int fa) { iindex++;pos[x]=iindex;vis[iindex]=x; for(int i=head[x];i!=-1;i=nxt[i]) { if(v[i]!=fa) { dep[v[i]]=dep[x]+w[i]; find(v[i],x); vis[++iindex]=x; } } } void rmq(int len) { for(int i=1;i<=len;i++) f[i][0]=dep[vis[i]]; for(int j=1;(1<<j)<=len;j++) { for(int i=1;(i+(1<<j))<=len;i++) { f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } int lca(int x,int y) { x=pos[x];y=pos[y];if(x>y) swap(x,y); int t=log2[y-x+1]; return min(f[x][t],f[y-(1<<t)+1][t]); } void work() { scanf("%d%d",&n,&m); 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); } find(1,0);rmq(iindex); for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); printf("%d\n",dep[x]+dep[y]-2*lca(x,y)); } } int main() { log2[1]=0;for(int i=2;i<maxn;i++) log2[i]=log2[i/2]+1; int T;scanf("%d",&T); for(int t=1;t<=T;t++) { init(); work(); } return 0; }
LCA做法
這裡不是很想贅述了,就是記錄每個點的深度(dep值),然後找兩個點的lca,x,y之間的距離就是dep[x]+dep[y]-2*lca(x,y)
直接上程式碼:
#include <iostream> #include <cstdio> #include <vector> using namespace std; const int maxn=40005; int n,m; struct node { int x,w; }; vector<node> v[maxn]; int p[maxn][32];int dep[maxn],d[maxn]; void prework() { for(int j=1;j<=31;j++) { for(int i=1;i<=n;i++) { p[i][j]=p[p[i][j-1]][j-1]; } } } void find(int x,int fa) { p[x][0]=fa;dep[x]=dep[fa]+1; for(int i=0;i<v[x].size();i++) { if(v[x][i].x!=fa) { d[v[x][i].x]=d[x]+v[x][i].w; find(v[x][i].x,x); } } } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); int i;for(i=1;(1<<i)<=dep[x];i++);i--; for(int j=i;j>=0;j--) if(dep[x]-(1<<j)>=dep[y]) x=p[x][j]; if(x==y) return x; for(int j=i;j>=0;j--) { if(p[x][j]!=p[y][j]) { x=p[x][j];y=p[y][j]; } } return p[x][0]; } void work() { scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int x,y,z;scanf("%d%d%d",&x,&y,&z);node k; k.x=y;k.w=z; v[x].push_back(k); k.x=x;v[y].push_back(k); } find(1,0);prework(); for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); int anc=lca(x,y); printf("%d\n",d[x]+d[y]-2*d[anc]); } } int main() { int T;scanf("%d",&T); for(int t=1;t<=T;t++) { work(); } return 0; }