NOIP 2013 【貨車運輸】



【題目大意】給定一張無向圖 以及若干個詢問 對於每個詢問求所有由節點u到節點v的路徑上邊權的最小值的最大值。

【題解】

  首先用構造一棵最大生成樹,這樣保證樹上兩個節點路徑邊權的最小值最大

  在最大生成樹上兩個節點之間只有一條路徑,所以只需要找路徑上邊權的最小值

 爲了快速的尋找最小值,利用樹上倍增的想法用f[j][i]記錄j的第2^i個祖先 並用 g[j][i]記錄j到f[j][i]的路徑上邊權的最小值

 然後在找公共祖先時順便就能處理最小值

【注意】可能不是一張連通圖,所有在lca時記得判斷兩個點是不是在同一棵樹裏

 詳見代碼

 

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <ctime>
#include <cmath>
#include <vector>
using namespace std;
int i,j,k,l,m,n,fx,fy,q,x,y,z,num;
int fa[10005],up[10005][20],first[10005],g[10005][20],h[10005];
struct info
  {
  	int fr,ar,l,next;
  }road[100050],tree[20005];
//vector <int> tree[10005];
bool cmp(info x,info y) {return x.l>y.l;}
int getfa(int x)
  {
  	if(fa[x]==x) return x;else return fa[x]=getfa(fa[x]);
  }
void dfs(int u)
  {
  	int i,v;
  	for (i=first[u];i;i=tree[i].next)
	   {
	   	 v=tree[i].ar;
	   	 if (!h[v])
	   	   {
	   	   	 h[v]=h[u]+1;
	   	   	 up[v][0]=u;g[v][0]=tree[i].l;
	   	   	 dfs(v);
		   }
	   } 
  }
int lca(int x,int y)
  {
  	if (getfa(x)!=getfa(y)) return -1;
  	int i,j,ans=1e9;
  	if (h[y]>h[x]) swap(x,y);
  	for (;h[x]>h[y];)
  	  {
  	  	for (i=0;h[up[x][i]]>=h[y];i++);i--;
  	  	ans=min(ans,g[x][i]);
  	  	x=up[x][i];
	  }
	for (;x!=y;)
	  {
	  	for (i=1;up[x][i]!=up[y][i];i++);i--;
	  	ans=min(ans,min(g[x][i],g[y][i]));
	  	x=up[x][i];y=up[y][i];
	  }
	return ans;
  }
int main() 
  {
  	scanf("%d%d",&n,&m);
  	for (i=1;i<=m;i++)
  	  scanf("%d%d%d",&x,&y,&z),road[i]=(info){x,y,z,0};
  	sort(road+1,road+m+1,cmp);
    for (i=1;i<=n;i++) fa[i]=i;
  	for (i=1;i<=m;i++)
  	  {
  	  	fx=getfa(road[i].fr);fy=getfa(road[i].ar);
  	  	if (fx!=fy)
  	  	  {
  	  	  	fa[fx]=fy;
			tree[++num]=(info){road[i].fr,road[i].ar,road[i].l,first[road[i].fr]};first[road[i].fr]=num;
			tree[++num]=(info){road[i].ar,road[i].fr,road[i].l,first[road[i].ar]};first[road[i].ar]=num;
		  }
	  }
	for (i=1;i<=n;i++)
	  if (!h[i])
	    {
	      h[i]=1;
	      dfs(1);
		  up[i][0]=i;g[i][0]=1e9; 
		}
	for (i=1;i<=15;i++) 
	  for (j=1;j<=n;j++) 
	    {
	      up[j][i]=up[up[j][i-1]][i-1];
		  g[j][i]=min(g[j][i-1],g[up[j][i-1]][i-1]);
		} 
    for (scanf("%d",&q);q;q--)
      {
      	scanf("%d%d",&x,&y);
      	printf("%d\n",lca(x,y));
	  }
  }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章