值得一做》一道类似于货车运输的题目(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
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
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 }
以上是关于值得一做》一道类似于货车运输的题目(BZOJ3732)(easy+)的主要内容,如果未能解决你的问题,请参考以下文章
值得一做》关于双标记线段树两三事BZOJ 1798 (NORMAL-)