【LCA &&問題解決]羅区1967運送

トピックポータル

トピック説明
国有N都市、1からnまでの番号は、都市間の双方向の道路が存在するmです。すべての道は重量制限と呼ばれる車の重量制限があります。Qは、複数の商品を輸送するまで、車両の重量制限を超えることなく、ドライバーは、すべての車を知りたい物資の輸送中のトラックがあります。


入力出力形式
入力形式:
最初の行は、mは、市内の道路やメートルを表しnは国家、nは2つの整数で区切られたスペースがあります。
次の3行それぞれm個の整数X、Y、スペースで区切られた2つの整数のそれぞれの間のz、重量制限があるX、Zに都会番号のY番号へのパスを表します。注:xがyと等しくない、二つの都市間の道路の数であってもよいです。
整数qはある次の行は、Qは、貨物トラックの必要性を表明しました。
スペースで区切られた間に2つの整数x、yは次Q線は、Y、都市xから物資を輸送するトラックの必要性を示し、注意:xがyと等しくありません。


出力形式:
Qラインの合計は、各トラックのための表す各整数は、最大荷重です。トラックが目的地に到達できない場合は、出力-1。


分析:2点間の距離が最小重量パス、あなたが欲しい最大重量であるため、その最も小さい最大で、我々は最大のスパニングツリーを考えます。私たちは、新しいマップは、LCAレコードの重みを倍増し、父親に対応した上で実行し、最大のスパニングツリーの再構築されたマップを実行します。

私たちは、使用しよう F A [ ] [ J ] 4 [C] [J] 上記i番目の点を示します 2 J 2 ^ J 世代のポイントは何ですか、その後、 メートル インクルード [ ] [ J ] I [i]は[J] 上方i番目の点を示します 2 J 2 ^ J 何(最小最大)最小重み生成があります

私たちは、次の式を起動することができます。

F A [ ] [ J ] = F A [ F A [ ] [ J - 1 ] ] [ J - 1 ] 4 [C] [J] = 4 [4 [C] [J-1] [J-1]
メートル インクルード [ ] [ J ] = メートル n個 メートル インクルード [ ] [ J - 1 ] メートル インクルード [ F A [ ] [ J - 1 ] ] [ J - 1 ] そして[I] [J] =分(MO [I]、[J-1]、および[FA [I] [J-1] [J-1])

私たちはもう一度LCAに求めて倍増ツリーにこれらの2つの式の事前実行を必要とします

次に、具体的なコードは次のように:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int fa[100010][20];
int f[100010];
bool vis[100010];
int mo[100010][20];
struct node{
    int x,y,v;
}e1[1000010];
struct node1{
    int y,Next,v;
}e[1000100];
int cnt=0,len=0;
int linkk[100010];
int d[100010];
int d1[100010];
bool mycmp(node x,node y){
    return x.v>y.v;
}
int getfa(int k){
    return k==f[k]?k:f[k]=getfa(f[k]); 
}
void insert(int x,int y,int v){
    e[++len].Next=linkk[x];
    linkk[x]=len;
    e[len].y=y;
    e[len].v=v;
}
void dfs(int x,int de){
	if (vis[x]) return;
	vis[x]=1;
    d[x]=de;
    for (int i=linkk[x];i;i=e[i].Next){
	    int y=e[i].y;
	    if (y==fa[x][0]) continue;
	    fa[y][0]=x;
	    mo[y][0]=e[i].v;
	    dfs(y,de+1);
	}
}
void find_fa(){
    for (int j=1;j<=19;j++)
      for (int i=1;i<=n;i++)
         fa[i][j]=fa[fa[i][j-1]][j-1],mo[i][j]=min(mo[i][j-1],mo[fa[i][j-1]][j-1]);
}
int lca(int u,int v){
	if (getfa(u)!=getfa(v)) return -1;
	int ans=10000000;
    if (d[u]>d[v]) swap(u,v);
    for (int i=19;i>=0;i--)
      if (d[fa[v][i]]>=d[u]) ans=min(ans,mo[v][i]),v=fa[v][i];
    if (u==v) return ans;
    for (int i=19;i>=0;i--)
      if (fa[u][i]!=fa[v][i]) ans=min(ans,min(mo[u][i],mo[v][i])),u=fa[u][i],v=fa[v][i];
    return min(ans,min(mo[u][0],mo[v][0]));
}
int main(){
    scanf("%d %d",&n,&m);
    for (int i=1,x,y,z;i<=m;i++) scanf("%d %d %d",&x,&y,&z),e1[++cnt]=(node){x,y,z},e1[++cnt]=(node){y,x,z};
    sort(e1+1,e1+cnt+1,mycmp);
    for (int i=1;i<=n;i++) f[i]=i;
    for (int i=1;i<=cnt;i++){
	    int x=getfa(e1[i].x),y=getfa(e1[i].y);
	    if (x!=y)
	      f[x]=y,insert(x,y,e1[i].v),insert(y,x,e1[i].v);//最大生成树建边
	}
	int root=1;
    for (int i=1;i<=n;i++)
      if (!vis[i]){
      	  d[i]=1;
	      dfs(i,1);
	      fa[i][0]=i;
	      mo[i][0]=10000000;
	  }//可能是森林,搜索未搜索的点,并计算出深度 
	find_fa();//预处理出fa数组 
	int q;
	scanf("%d",&q);
	for (int i=1,x,y;i<=q;i++) scanf("%d %d",&x,&y),printf("%d\n",lca(x,y));//输出它们最近公共祖先的权值,此时即最小的最大载重 
}

おすすめ

転載: blog.csdn.net/huang_ke_hai/article/details/87334427