1. 程式人生 > >「NOIP2013」「LuoguP1967」貨車運輸(最大生成樹 倍增 LCA

「NOIP2013」「LuoguP1967」貨車運輸(最大生成樹 倍增 LCA

!= noi ora 輸出 tdi ott 限制 格式 否則

題目描述

AA國有nn座城市,編號從 11到nn,城市之間有 mm 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 qq 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。

輸入輸出格式

輸入格式:

第一行有兩個用一個空格隔開的整數n,mn,m,表示 AA 國有nn 座城市和 mm 條道路。

接下來 mm行每行33個整數 x, y, zx,y,z,每兩個整數之間用一個空格隔開,表示從 xx號城市到yy號城市有一條限重為 zz 的道路。註意: xx 不等於 yy,兩座城市之間可能有多條道路 。

接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。

接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,註意:x 不等於 y 。

輸出格式:

共有 qq 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨車不能到達目的地,輸出-11。

輸入輸出樣例

輸入樣例#1: 復制
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
輸出樣例#1: 復制
3
-1
3

說明

對於 30\%30%的數據,0 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000;

對於 60\%60%的數據,0 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<n<1,000,0<m<50,000,0<q<1,000;

對於 100\%100%的數據,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,0000<n<10,000,0<m<50,000,0<q<30,000,0z100,000。

題解

跑個最大生成樹,然後對於每次詢問在最大生成樹上走樹上路徑,就能保證運的最重。

所以對於每次詢問,如果兩點在一個聯通塊上,輸出樹上路徑的最小邊權值,否則輸出-1就行了。

實現過程很像「LuoguP4180」 【模板】嚴格次小生成樹[BJWC2010](倍增 LCA Kruscal,但是要好碼一丟丟。

  1 /*
  2 qwerta 
  3 P1967 貨車運輸 Accepted 
  4 100
  5 代碼 C++,1.84KB
  6 提交時間 2018-11-02 22:17:58
  7 耗時/內存 453ms, 2548KB
  8 */
  9 #include<algorithm>
 10 #include<iostream>
 11 #include<cstdio>
 12 #include<cmath>
 13 using namespace std;
 14 const int MAXN=10000+3,MAXM=50000+3;
 15 struct emm{
 16     int x,y,l;
 17 }b[MAXM];
 18 bool cmpb(emm qaq,emm qwq){
 19     return qaq.l>qwq.l;
 20 }
 21 int fa[MAXN];
 22 int fifa(int x)
 23 {
 24     if(fa[x]==x)return x;
 25     return fa[x]=fifa(fa[x]);
 26 }
 27 struct ahh{
 28     int e,f,l;
 29 }a[2*MAXN];
 30 int h[MAXN];
 31 int tot=0;
 32 void con(int x,int y,int l)
 33 {
 34     a[++tot].f=h[x];
 35     h[x]=tot;
 36     a[tot].e=y;
 37     a[tot].l=l;
 38     a[++tot].f=h[y];
 39     h[y]=tot;
 40     a[tot].e=x;
 41     a[tot].l=l;
 42     return;
 43 }
 44 int d[MAXN];
 45 int f[MAXN][13];
 46 int mi[MAXN][13];
 47 void dfs(int x)
 48 {
 49     for(int i=h[x];i;i=a[i].f)
 50     if(!d[a[i].e])
 51     {
 52         d[a[i].e]=d[x]+1;
 53         f[a[i].e][0]=x;
 54         mi[a[i].e][0]=a[i].l;
 55         dfs(a[i].e);
 56     }
 57     return;
 58 }
 59 bool sf[MAXN];
 60 int main()
 61 {
 62     //freopen("a.in","r",stdin);
 63     int n,m;
 64     scanf("%d%d",&n,&m);
 65     for(int i=1;i<=m;++i)
 66     {
 67         scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].l);
 68     }
 69     sort(b+1,b+m+1,cmpb);
 70     for(int i=1;i<=n;++i)
 71         fa[i]=i;
 72     int k=n-1,i=0;
 73     while(k&&i<=m)
 74     {
 75         i++;
 76         int u=fifa(b[i].x),v=fifa(b[i].y);
 77         if(u!=v)
 78         {
 79             //cout<<i<<" "<<b[i].x<<" "<<b[i].y<<" "<<b[i].l<<endl;
 80             fa[u]=v;
 81             con(b[i].x,b[i].y,b[i].l);
 82             k--;
 83         }
 84     }
 85     for(int s=1;s<=n;++s)
 86     if(!sf[fifa(s)])
 87     {
 88         sf[fifa(s)]=1;
 89         d[s]=1;
 90         dfs(s);
 91     }
 92     for(int j=1;j<=10;++j)
 93     for(int i=1;i<=n;++i)
 94     {
 95         f[i][j]=f[f[i][j-1]][j-1];
 96         mi[i][j]=min(mi[i][j-1],mi[f[i][j-1]][j-1]);
 97     }
 98     int q;
 99     scanf("%d",&q);
100     while(q--)
101     {
102         int u,v;
103         scanf("%d%d",&u,&v);
104         if(fifa(u)!=fifa(v)){printf("-1\n");continue;}
105         if(d[u]<d[v])swap(u,v);
106         int ans=1e6+2333;
107         for(int j=10;j>=0;--j)
108         if(d[u]-d[v]>=(1<<j))
109         {
110             ans=min(ans,mi[u][j]);
111             u=f[u][j];
112         }
113         if(u==v){printf("%d\n",ans);continue;}
114         for(int j=10;j>=0;--j)
115         if(f[u][j]!=f[v][j])
116         {
117             ans=min(ans,mi[u][j]);
118             u=f[u][j];
119             ans=min(ans,mi[v][j]);
120             v=f[v][j];
121         }
122         ans=min(ans,mi[u][0]);
123         ans=min(ans,mi[v][0]);
124         printf("%d\n",ans);
125     }
126     return 0;
127 }

「NOIP2013」「LuoguP1967」貨車運輸(最大生成樹 倍增 LCA