#1T2最小生成树改错
啊啊啊啊啊啊
题目传送门
思路赛时就胡出来了,先构造最小生成树。对于每一次查询,答案就是两个节点在最小生成树上的链中最长边的权值。
权值的查找正解是在倍增跳lca的过程中更新,我先尝试树剖没剖出来,又去学了倍增,在120多行的诗山代码中出现了没建双向边和log值访问越界的问题,在老师的帮助下调傻了
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+5;
const int L=20;
int fa[N];
int up[L][N],maxn[L][N];
int dep[N];
//最开始记录边的结构体
struct node{
int x,y,w;
}e[N],q[N];
//链式前向星结构体
struct edge{
int to,nxt,v;
}chk[N];
//最小生成树的并查集
bool cmp(node a,node b){
return a.w<b.w;
}
int findF(int x){
if(x==fa[x]) return x;
fa[x]=findF(fa[x]);
return fa[x];
}
int head[N];
int n,m,u,v,w,cnt,sum,ant;
//最小生成树的加边函数
void add(int x,int y,int w){
chk[++ant].to=y;
chk[ant].nxt=head[x];
chk[ant].v=w;
head[x]=ant;
}
//倍增预处理
void dfs(int u,int ff,int elen){
// cout<<u<<':';
up[0][u]=ff;
maxn[0][u]=elen;
dep[u]=dep[ff]+1;
for(int i=head[u];i;i=chk[i].nxt){
int dd=chk[i].to;
// cout<<dd<<' ';
if(dd==ff) continue;
dfs(dd,u,chk[i].v);
}
// cout<<'\n';
}
//预处理
void pp(int n,int root){
dep[root] = -1;
dfs(root,root,0);
for(int k=1;k<L;k++){
for(int x=1;x<=n;x++){
up[k][x]=up[k-1][up[k-1][x]];
maxn[k][x]=max(maxn[k-1][x],maxn[k-1][up[k-1][x]]);
}
}
}
//求长度
int getedge(int u,int v){
int res=0;
if(dep[u]<dep[v]){
swap(u,v);
}
for(int k=L-1;k>=0;k--){
if(dep[up[k][u]]>=dep[v]){
res=max(res,maxn[k][u]);
u=up[k][u];
}
}
if(u==v) return res;
for(int k=L-1;k>=0;k--){
if(up[k][u]!=up[k][v]){
res=max(res,maxn[k][u]);
res=max(res,maxn[k][v]);
u=up[k][u];
v=up[k][v];
}
}
res=max(res,maxn[0][u]);
res=max(res,maxn[0][v]);
// cout<<up[0][u]<<'\n';
return res;
}
int main(){
freopen("mst.in","r",stdin);
freopen("mst.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin >> n >> m;
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
cin >> u >> v >>w;
e[++cnt].x=u;e[cnt].y=v;e[cnt].w=w;
e[++cnt].x=v;e[cnt].y=u;e[cnt].w=w;
}
//复制一份查找用
for(int i=1;i<=cnt;i++){
q[i].w=e[i].w;q[i].x=e[i].x;q[i].y=e[i].y;
}
sort(e+1,e+cnt+1,cmp);
int k=0,tot=0;
for(int i=1;i<=cnt;i++){
if(findF(e[i].x)!=findF(e[i].y)){
tot+=e[i].w;
fa[findF(e[i].x)]=e[i].y;
add(e[i].x,e[i].y,e[i].w);//建立最小生成树
add(e[i].y,e[i].x,e[i].w);
k++;
if(k==n-1) break;
}
}
pp(n,1);
//查找
for(int i=1;i<=cnt;i+=2){
int xx=q[i].x;
int yy=q[i].y;
cout << getedge(xx,yy) << '\n';
}
return 0;
}