POJ - 1986 Distance Queries 倍增求LCA
生活随笔
收集整理的這篇文章主要介紹了
POJ - 1986 Distance Queries 倍增求LCA
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意還是很有病的,說了半天后邊的方向都沒用的,意思就是跟樣例一樣求兩點間的距離,裸的LCA
兩個點x,y的距離=dis[x]+dis[y]-2*dis[LCA(x,y)];
三個點x,y,z的距離=dis[x]+dis[y]+dis[z]-dis(lca(x,y))-dis(lca(y,z))-dis(lca(x,z));
倍增的思想是感覺跟RMQ很像,就是首先建數存路徑與各節點深度,首先來說最暴力的方法就是將兩點中深度大的點跳到與深度小的點一樣深度,然后兩個點一起往上跳一層一層的跳,最后總能跳到同一個位置。like this,但是顯然復雜度大的不談。
if(dep[u]<dep[v]) swap(u,v);
int x=(dep[u]-dep[v]);
while(x--)u=f[u];
while(u!=v)
{u=f[u];v=f[v];
}
所以說倍增的方法就是通過一個二維的f[u][i]數組來表示u節點往上跳2^i方個節點。
那么比如說一個深度為10的u點和一個深度為5的v點,先將u點跳到v點的深度,就需要u先往上跳5個,轉化成二進制不就是101.
那么u先往上跳一格f變成 f[u][0],然后再想上跳4格就是2的2次方 f[f[u][0]] [2],然后就跳到一個層了。
然后兩個一起向上跳也是一樣的,不再是一個一個的向上跳,而是盡量以2的n次方向上跳,也就是說深度差為int范圍內只需跳不超過32次。所以就大大簡化了復雜度,并且是在線 的。
那么怎么求f數組呢,在理解就是f[u][i]當i>0時,f[u][i]=f[f[u][i-1]] [i-1]類似于折半的感覺就能把f數組提前處理出來。
代碼
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define inff 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define PI 3.14159265358979323846
#define me(a,b) memset(a,b,sizeof(a))
#define min4(a,b,c,d) min(min(a,b),min(c,d))
#define min3(x,y,z) min(min(x,y),min(y,z))
const int dir[4][2]= {0,-1,-1,0,0,1,1,0};
typedef long long ll;
const ll inFF=9223372036854775807;
typedef unsigned long long ull;
using namespace std;
const int maxn=4e4+5;
int f[maxn][20],d[maxn],head[maxn],dis[maxn];//d表示深度,dis表示到root距離,f表示父節點關系
int n,m,sign;
struct node
{int to,p,val;
}edge[maxn<<1];
void init()
{sign=0;for(int i=1;i<=n;i++)head[i]=-1;
}
void add(int u,int v,int val)
{edge[sign]=node{v,head[u],val};head[u]=sign++;
}
void dfs(int u)
{for(int i=head[u];~i;i=edge[i].p){int v=edge[i].to;if(v==f[u][0]) continue;d[v]=d[u]+1;dis[v]=edge[i].val+dis[u];f[v][0]=u;//f[v][0]就是v的father就是udfs(v);}
}
void getf() //得到數組也是上述的那個理解
{for(int j=1;(1<<j)<=n;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int a,int b)
{if(d[a]<d[b]) swap(a,b);//把a變成那個深度大的int x=d[a]-d[b];//距離差for(int i=0;(1<<i)<=x;i++)if((1<<i)&x) a=f[a][i];//把a跳到跟b一樣的深度if(a!=b){for(int i=(int)log2(n);i>=0;i--)//這個要從大的步子往小步子跳if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];a=f[a][0];}return a;//返回lca
}
int main()
{char ch;int x,y,z,k;while(cin>>n>>m){init();for(int i=1;i<=m;i++) scanf("%d %d %d %c",&x,&y,&z,&ch),add(x,y,z),add(y,x,z);f[1][0]=1,dis[1]=0,d[1]=1;dfs(1);getf();cin>>k;for(int i=1;i<=k;i++){scanf("%d %d",&x,&y);cout<<dis[x]+dis[y]-2*dis[lca(x,y)]<<endl;}}return 0;
}
?
總結
以上是生活随笔為你收集整理的POJ - 1986 Distance Queries 倍增求LCA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 2586 How far awa
- 下一篇: HDU - 3078 Network