NOIp2013 货车运输 By cellur925

题目传送门

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

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

 

思路

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

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

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

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

 

实现


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

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

code

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxm 50090
  7 #define maxn 10090
  8 
  9 using namespace std;
 10 
 11 int n,m,Q,tot,t;
 12 int head[maxn],d[maxn],f[maxn][31],fa[maxn],g[maxn][31];
 13 bool vis[maxn];
 14 struct cellur{
 15     int f,t,w;
 16 }e[maxm];
 17 struct node{
 18     int to,next,val;
 19 }edge[maxn<<1];
 20 
 21 bool cmp(cellur a,cellur b)
 22 {
 23     return a.w>b.w;
 24 } 
 25 
 26 void add(int x,int y,int z)
 27 {
 28     edge[++tot].to=y;
 29     edge[tot].next=head[x];
 30     head[x]=tot;
 31     edge[tot].val=z;
 32 }
 33 
 34 int getf(int x)
 35 {
 36     if(fa[x]==x) return x;
 37     else return fa[x]=getf(fa[x]);
 38 }
 39 
 40 void Kruskal()
 41 {
 42     for(int i=1;i<=n;i++) fa[i]=i;
 43     sort(e+1,e+1+m,cmp);
 44     int cnt=0;
 45     for(int i=1;i<=m;i++)
 46     {
 47         if(cnt==n-1) break;
 48         int pp=getf(e[i].f);
 49         int qq=getf(e[i].t);
 50         if(pp==qq) continue;
 51         cnt++;
 52         fa[qq]=pp;
 53         add(e[i].f,e[i].t,e[i].w),add(e[i].t,e[i].f,e[i].w);
 54     }
 55 }
 56 
 57 void bfs(int s)
 58 {
 59     queue<int>q;
 60     q.push(s);d[s]=1;
 61     while(!q.empty())
 62     {
 63         int u=q.front();q.pop();
 64         for(int i=head[u];i;i=edge[i].next)
 65         {
 66             int v=edge[i].to;
 67             if(d[v]) continue;
 68             d[v]=d[u]+1;
 69             f[v][0]=u;g[v][0]=edge[i].val;
 70             for(int j=1;j<=t;j++)
 71             {
 72                 f[v][j]=f[f[v][j-1]][j-1];
 73                 g[v][j]=min(g[f[v][j-1]][j-1],g[v][j-1]);
 74             }
 75             q.push(v);
 76         }
 77     }
 78 }
 79 
 80 int lca(int x,int y)
 81 {
 82     int num=1e9;
 83     if(d[x]<d[y]) swap(x,y);
 84     for(int i=t;i>=0;i--)
 85         if(d[f[x][i]]>=d[y]) num=min(num,g[x][i]),x=f[x][i];
 86     if(x==y) return num;
 87     for(int i=t;i>=0;i--)
 88         if(f[x][i]!=f[y][i])
 89         {
 90             num=min(num,g[x][i]);
 91             num=min(num,g[y][i]);
 92             x=f[x][i],y=f[y][i];
 93         } 
 94     return min(num,min(g[x][0],g[y][0]));
 95 }
 96 
 97 int main()
 98 {
 99     freopen("truck.in","r",stdin);
100     freopen("truck.out","w",stdout);
101     scanf("%d%d",&n,&m);
102     t=log2(n)+1;
103     for(int i=1;i<=m;i++)
104         scanf("%d%d%d",&e[i].f,&e[i].t,&e[i].w);
105     Kruskal();
106     memset(g,63,sizeof(g));
107     for(int i=1;i<=n;i++) if(!d[i]) bfs(i);
108 //    for(int i=1;i<=n;i++) printf("%d ",g[i][2]);
109 //    return 0;
110     scanf("%d",&Q);
111     while(Q--)
112     {
113         int x=0,y=0;
114         scanf("%d%d",&x,&y);
115         int pp=getf(x);
116         int qq=getf(y);
117         if(pp!=qq) {printf("-1\n");continue;}    
118         printf("%d\n",lca(x,y));
119     }
120     return 0;
121 }
View Code

$bfs$也能解决不连通的问题:不bfs一次,而是让每个点都有深度。

11.6考试的时候边大小开小了&&LCA写错板子了hhh

posted @ 2018-08-20 12:03  cellur925&Chemist  阅读(164)  评论(0编辑  收藏  举报