题目描述
给定一个点数为,边数为,权值不超过的带权连通图,没有自环与重边。
现在要求对于每一条边求出,这条边的边权最大为多少时,它还能出现在所有可能的最小生成树上,如果对于任意边权都出现,则输出。 (


建出最小生成树
讨论这条边在不在最小生成树上

若不在 那么在这条链上应该有边比它小,所以等于链上最大边权
若在 那么它应该比所有经过这条边的非树边小
因为如果一条链经过,那么它就有机会替代
第一种我们直接树上倍增
第二种求经过的最大数,设为,可以树链剖分
也可以将链从小到大排序,先覆盖的就不用改了
那么,我们用并查集实现这个合并
每次加入一条链,设
也就是说,我们将合并,标记他们的值
我们每次从跳到
因为合并过,所有它们的值已被确定,不用再修改
所以我们只用将修改,注意边权下放到点
然后将合并
复杂度,因为每个点只会被合并一次

#include <bits/stdc++.h>
#define ri register int
#define ll long long
using namespace std;
const int Maxn=5e5;
const int Lgn=20;
const int Maxm=2e6;
const int Inf=1e9+1;
struct Edge {
    int x,y,z,id;
}e[Maxm+5];
int lt[Maxn+5],nt[2*Maxn+5],ed[2*Maxn+5],val[2*Maxn+5],cnt;
int st[Maxn+5][Lgn+5],mx[Maxn+5][Lgn+5];
int father[Maxn+5],size[Maxn+5],son[Maxn+5],dep[Maxn+5],top[Maxn+5],dfn[Maxn+5],vt;
int link[Maxm+5],mark[Maxm+5],v[Maxn+5],n,m;
bool cmp(Edge a,Edge b) {
    return a.z<b.z;
}
void addedge(int x,int y,int z) {
    ed[++cnt]=y;nt[cnt]=lt[x];lt[x]=cnt;
    val[cnt]=z;
}
int getfather(int v) {
    return father[v]==v?v:father[v]=getfather(father[v]);
}
void dfs1(int u,int fa) {
    dep[u]=dep[fa]+1;st[u][0]=fa;
    int t=ceil(log2(dep[u]));
    for(ri i=1;i<=t;i++) {
        st[u][i]=st[st[u][i-1]][i-1];
        mx[u][i]=max(mx[u][i-1],mx[st[u][i-1]][i-1]);
    }
    size[u]=1;
    int maxn=0;
    for(ri i=lt[u];i;i=nt[i]) {
        int v=ed[i];
        if(v!=fa) {
            mx[v][0]=val[i];
            dfs1(v,u);
            if(size[v]>maxn)maxn=size[v],son[u]=v;
            size[u]+=size[v];    
        }
    }
}
void dfs2(int u,int fa,int tp) {
    top[u]=tp;dfn[u]=++vt;
    if(son[u])dfs2(son[u],u,tp);
    for(ri i=lt[u];i;i=nt[i]) {
        int v=ed[i];
        if(v!=fa&&v!=son[u])dfs2(v,u,v);
    }
}
int lca(int x,int y) {
    while(top[x]!=top[y]) {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=st[top[x]][0];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}
void modify(int x,int y,int z) {
    int o=lca(x,y);
    while(1) {
        x=getfather(x);
        if(dep[x]<=dep[o])break;
        v[x]=z;
        father[x]=st[x][0],x=getfather(x);
    }
    while(1) {
        y=getfather(y);
        if(dep[y]<=dep[o])break;
        v[y]=z;
        father[y]=st[y][0],y=getfather(y);
    }
}
int getmax(int x,int y) {
    int o=lca(x,y);
    int depx=ceil(log2(dep[x])),mx1=0;
    for(ri i=depx;i>=0;i--)
        if(dep[st[x][i]]>dep[o]) {
            mx1=max(mx1,mx[x][i]);
            x=st[x][i];
        }
    if(x!=o)mx1=max(mx1,mx[x][0]);
    int depy=ceil(log2(dep[y])),mx2=0;
    for(ri i=depy;i>=0;i--)
        if(dep[st[y][i]]>dep[o]) {
            mx2=max(mx2,mx[y][i]);
            y=st[y][i];
        }
    if(y!=o)mx2=max(mx2,mx[y][0]);
    return max(mx1,mx2);
}
void kruskal() {
    sort(e+1,e+m+1,cmp);
    for(ri i=1;i<=n;i++)father[i]=i;
    for(ri i=1;i<=m;i++) {
        link[e[i].id]=i;
        int x=getfather(e[i].x),y=getfather(e[i].y);
        if(x!=y) {
            addedge(e[i].x,e[i].y,e[i].z);
            addedge(e[i].y,e[i].x,e[i].z);
            father[y]=x;
            mark[e[i].id]=1;
        }
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for(ri i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z),e[i].id=i;
    kruskal();
    dfs1(1,0);
    dfs2(1,0,1);
    for(ri i=1;i<=n;i++)father[i]=i,v[i]=Inf;
    for(ri i=1;i<=m;i++)
        if(!mark[e[i].id])modify(e[i].x,e[i].y,e[i].z);
    for(ri i=1;i<=m;i++) {
        int s=link[i];
        if(mark[i]) {
            int u=dep[e[s].x]>dep[e[s].y]?e[s].x:e[s].y;
            int ans=v[u];
            printf("%d\n",ans==Inf?-1:ans-1);
        }
        else {
            int ans=getmax(e[s].x,e[s].y);
            printf("%d\n",ans-1);
        }
    }
    return 0;
}