题目大意:给定一个n个点m条边的无向连通图,k次询问两点之间所有路径中最长边的最小值
NOIP2013 货车运输,几乎就是原题。。。只不过最小边最大改成了最大边最小。。。
首先看到最大值最小第一反应二分答案 但是二分答案O(kmlogn)明显做不了 这里我们考虑最小生成树
先生成一棵最小生成树,然后每次询问利用倍增LCA求出路径上的最大权值即可
本蒟蒻居然把LCA写挂了。。。 而且样例还过了。。。 伤不起啊。。。
90%达成 剩下一道刷点啥呢。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct edge{ int x,y,f; bool operator < (const edge &y) const { return f < y.f; } }edges[30300]; struct abcd{ int to,f,next; }table[30300]; int head[15100],tot; int n,m,k; int fa[15100][20],f_max[15100][20],dpt[15100]; int belong[15100]; int find(int x) { if(!belong[x]||belong[x]==x) return belong[x]=x; return belong[x]=find(belong[x]); } void add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void dfs(int x) { int i; dpt[x]=dpt[fa[x][0]]+1; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x][0]) continue; fa[table[i].to][0]=x; f_max[table[i].to][0]=table[i].f; dfs(table[i].to); } } int Query(int x,int y) { int j,re=0; if(dpt[x]<dpt[y]) swap(x,y); for(j=14;~j;j--) if(dpt[ fa[x][j] ]>=dpt[y]) re=max(re,f_max[x][j]),x=fa[x][j]; if(x==y) return re; for(j=14;~j;j--) if(fa[x][j]!=fa[y][j]) { re=max(re,f_max[x][j]); re=max(re,f_max[y][j]); x=fa[x][j]; y=fa[y][j]; } re=max(re,f_max[x][0]); re=max(re,f_max[y][0]); return re; } int main() { int i,j,x,y; cin>>n>>m>>k; for(i=1;i<=m;i++) scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f); sort(edges+1,edges+m+1); for(i=1;i<=m;i++) { int fx=find(edges[i].x),fy=find(edges[i].y); if(fx!=fy) { belong[fx]=fy; add(edges[i].x,edges[i].y,edges[i].f); add(edges[i].y,edges[i].x,edges[i].f); } } dfs(1); for(j=1;j<=14;j++) for(i=1;i<=n;i++) fa[i][j]=fa[ fa[i][j-1] ][j-1],f_max[i][j]=max( f_max[i][j-1] , f_max[ fa[i][j-1] ][j-1] ); for(i=1;i<=k;i++) { scanf("%d%d",&x,&y); printf("%d\n", Query(x,y) ); } }
时间: 2024-10-07 05:17:49