您的位置:首页 > 其它

NOIp2013 货车运输 By cellur925

2018-08-20 12:03 323 查看

题目传送门

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: