值得一做》一道类似于货车运输的题目(BZOJ3732)(easy+)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了值得一做》一道类似于货车运输的题目(BZOJ3732)(easy+)相关的知识,希望对你有一定的参考价值。

  这是一道模板套模板的题目,只要会LCA和最小生成树就可以做,水题

  直接先甩题目

Description

给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。 
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).

现在有 K个询问 (1 < = K < = 15,000)。 
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input

第一行: N, M, K。 
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。 
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Output

 对每个询问,输出最长的边最小值是多少。

Sample Input

6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1

Sample Output

5
5
5
4
4
7
4
5

HINT

1 <= N <= 15,000 
1 <= M <= 30,000 
1 <= d_j <= 1,000,000,000 
1 <= K <= 15,000 

  这道题比较困难的是如何想出可行解法,题目中说最大权边最小,而又有很多询问,所以二分答案肯定不行,所以考虑使用一些奇怪的技巧,

  我们知道两点之间的这条最大值最小的路径是唯一的,所以我们可以从这方面入手。

  显然的,通过一些基本证明,我们可以得知我们要求的实际上是最小生成树,那么既然已经有树形结构了,那么两点之间的路径可以通过LCA轻易的找到,用倍增即可维护最值

  直接给出代码

技术分享
 1 #include<stdio.h>
 2 #include<algorithm>
 3 using namespace std;
 4 struct shit{
 5     int aim,from,lon,next;
 6 }e[20000],s[61000];
 7 struct ass{
 8     int fat,mx;
 9 }f[30][20000];
10 int point,dep[20000],fa[20000],fff[20000],cnt,head[20000],n,m,k;
11 bool vis[20000];
12 int LCA_(int x,int y)
13 {
14     int mather_fucker=0;
15     if(dep[x]>dep[y])swap(x,y);
16     for(int i=14;~i;--i)
17     if(dep[f[i][y].fat]>=dep[x])
18     {
19         mather_fucker=max(mather_fucker,f[i][y].mx);
20         y=f[i][y].fat;
21     }
22     if(y==x)return mather_fucker;
23     for(int i=15;~i;--i)
24     if(f[i][y].fat!=f[i][x].fat){
25         mather_fucker=max(mather_fucker,max(f[i][y].mx,f[i][x].mx));
26         y=f[i][y].fat;
27         x=f[i][x].fat;
28     }
29     mather_fucker=max(mather_fucker,max(f[0][y].mx,f[0][x].mx));
30     return mather_fucker;
31 }
32 void fuck(int x,int y,int z)
33 {
34     e[++point].aim=y;e[point].from=x;e[point].lon=z;e[point].next=head[x];head[x]=point;
35     e[++point].aim=x;e[point].from=y;e[point].lon=z;e[point].next=head[y];head[y]=point;
36 }
37 void get(int w,int x,int y,int z)
38 {
39     s[w].aim=y,s[w].from=x,s[w].lon=z;
40 }
41 int find(int x)
42 {
43     return fa[x]==x?x:fa[x]=find(fa[x]);
44 }
45 bool cmp(shit x,shit y)
46 {
47     if(x.lon<y.lon)return true;
48     else return false;
49 }
50 void work(int x,int d)
51 {
52     dep[x]=d;
53     vis[x]=true;
54     for(int i=head[x];i;i=e[i].next)
55     {
56         int u=e[i].aim;
57         if(vis[u])continue;
58         f[0][u].fat=x;
59         f[0][u].mx=e[i].lon;
60         work(u,d+1);
61     }
62 }
63 int main()
64 {
65     int a,b,c;
66     scanf("%d%d%d",&n,&m,&k);
67     for(int i=1;i<=m;i++)
68     {
69         scanf("%d%d%d",&a,&b,&c);
70         get(i,a,b,c);
71     }
72     for(int i=1;i<=n;i++)fa[i]=i;
73     sort(s+1,s+m+1,cmp);
74     for(int i=1;i<=m;++i)
75     {
76         a=find(s[i].aim);
77         b=find(s[i].from);
78         if(a==b)continue;
79         fa[a]=b;
80         fuck(a,b,s[i].lon);
81         ++cnt;
82         if(cnt==n-1)break;
83     }
84     f[0][n/2].fat=n/2,f[0][n/2].mx=0,dep[n/2]=1,vis[n/2]=true;
85     work(n/2,1);
86     for(int i=1;i<=15;i++)
87         for(int j=1;j<=n;j++)
88         {
89             f[i][j].fat=f[i-1][f[i-1][j].fat].fat;
90             f[i][j].mx=max(f[i-1][j].mx,f[i-1][f[i-1][j].fat].mx);
91         }
92     for(int i=1;i<=k;++i)
93     {
94         scanf("%d%d",&a,&b);
95         printf("%d\\n",LCA_(a,b));
96     }
97     return 0;
98 }
View Code

 

以上是关于值得一做》一道类似于货车运输的题目(BZOJ3732)(easy+)的主要内容,如果未能解决你的问题,请参考以下文章

值得一做》关于双标记线段树两三事BZOJ 1798 (NORMAL-)

值得一做》关于数学与递推 BZOJ1002 (BZOJ第一页计划)(normal+)

3287 货车运输

Codevs 3287 货车运输

[Codevs] 3287 货车运输

刷题总结——货车运输