NOIp2013 货车运输 By cellur925

题目传送门

A 国有 n 座城市,编号从 1 到 n ,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。

现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

思路

这题思路想明白了就很简单,一句话题意:求树上两点间路线中边长最小的边权。

首先,为什么是树呢?限重肯定越大越好,因此我们可以跑出图的最大生成树(Kruskal)

之后,我们就可以对于每次询问来求出路径上的最小边权(最多能运的货物重量),这里可以用到树上倍增法(求LCA时一起求了,虽然LCA不会直接用到,但也是要一起求出来的)

至于两点间是否能互达,就可以用并查集维护一下就行了!

实现


提交记录过于真实,从0到10到65到70到95到AC Orz

可能是我常数写丑了,所以在洛谷更新评测姬前以及不开氧气优化都会T两个点??

code

  1 // luogu-judger-enable-o2
  2 #include<cstdio>
  3 #include<algorithm>
  4 
  5 using namespace std;
  6 
  7 int n,m,Q,tot;
  8 int head[10090],vis[10090],fa[10090],d[10090];
  9 int f[10090][16],g[10090][16];
 10 struct Chemist{
 11     int f,t,w;
 12 }qwq[50090];
 13 struct node{
 14     int next,to,val;
 15 }edge[100090];
 16 
 17 bool cmp(Chemist A,Chemist B)
 18 {
 19     return A.w>B.w;
 20 }
 21 
 22 void add(int x,int y,int z)
 23 {
 24     edge[++tot].to=y;
 25     edge[tot].val=z;
 26     edge[tot].next=head[x];
 27     head[x]=tot;
 28 }
 29 
 30 int getf(int x)
 31 {
 32     if(fa[x]==x) return x;
 33     else return getf(fa[x]);
 34 }
 35 
 36 void dfs(int u)
 37 {
 38     vis[u]=1;
 39     for(int i=head[u];i;i=edge[i].next)
 40     {
 41         int v=edge[i].to;
 42         if(!vis[v])
 43         {
 44             f[v][0]=u;
 45             g[v][0]=edge[i].val;
 46             d[v]=d[u]+1;
 47             dfs(v);
 48         }
 49     }
 50 }
 51 
 52 void Kruskal()
 53 {
 54     for(int i=1;i<=n;i++)
 55         fa[i]=i;
 56     sort(qwq+1,qwq+1+m,cmp);
 57     for(int i=1;i<=m;i++)
 58     {
 59         int pp=getf(qwq[i].f);
 60         int qq=getf(qwq[i].t);
 61         if(pp!=qq)
 62         {
 63             fa[qq]=pp;//f[pp]=qq;
 64             add(qwq[i].f,qwq[i].t,qwq[i].w);
 65             add(qwq[i].t,qwq[i].f,qwq[i].w);
 66         }
 67     }
 68     //连一条虚边
 69     for(int i=1;i<=n;i++)
 70         if(getf(i)!=getf(1)) add(1,i,0);
 71 }
 72 
 73 int lca(int x,int y)
 74 {
 75     int tmp=1e9;
 76     if(d[x]<d[y]) swap(x,y);
 77     for(int j=0;j<=13;j++)
 78         if((1<<j)&(d[x]-d[y]))
 79         {
 80             tmp=min(tmp,g[x][j]);
 81             x=f[x][j];
 82         }
 83     if(x==y) return tmp;
 84     for(int j=14;j>=0;j--)
 85         if(f[x][j]!=f[y][j])
 86         {
 87             tmp=min(tmp,g[x][j]);
 88             tmp=min(tmp,g[y][j]);
 89             x=f[x][j];
 90             y=f[y][j];
 91         }
 92     tmp=min(tmp,g[x][0]);
 93     tmp=min(tmp,g[y][0]);
 94     return tmp;
 95 }
 96 
 97 int main()
 98 {
 99     scanf("%d%d",&n,&m);
100     for(int i=1;i<=m;i++)
101         scanf("%d%d%d",&qwq[i].f,&qwq[i].t,&qwq[i].w);
102     Kruskal();
103     dfs(1);//树上倍增的准备工作
104     for(int j=1;j<=14;j++)
105         for(int i=1;i<=n;i++)
106         {
107             f[i][j]=f[f[i][j-1]][j-1];
108             g[i][j]=min(g[i][j-1],g[f[i][j-1]][j-1]);
109         }
110     scanf("%d",&Q);
111     while(Q--)
112     {
113         int l=0,r=0,ans=0;
114         scanf("%d%d",&l,&r);
115         ans=lca(l,r);
116         if(ans==0) printf("-1\n");
117         else printf("%d\n",ans);
118     }
119     return 0;
120 }
View Code

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9504852.html