1 条题解

  • 0
    @ 2026-5-7 23:14:26

    这里介绍一种只使用了倍增,不需要任何线段树、树链剖分等更高级的技巧的解法。

    对于一条替代道路 (u,v,w)(u,v,w),它对且只对 uuvv 的路径上的边产生影响。也就是说,这相当于对于 uuvv 的路径上的所有边 ii,设这条边的答案为 gig_i,执行操作 gimin(gi,w)g_i\leftarrow \min(g_i,w)。我们可以把路径拆分为 uuvv 到最近公共祖先的两条路径,然后用倍增维护即可。

    #include<bits/stdc++.h>
    using namespace std;
    vector<int>G[50505];
    int n,m,f[50505][20],g[50505][20],d[50505],ans[50505];
    map<pair<int,int>,int>M;
    void dfs(int u,int p){
    	d[u]=d[p]+1;
    	for(int v:G[u])if(v!=p)f[v][0]=u,dfs(v,u);
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1,u,v;i<n;i++)cin>>u>>v,G[u].push_back(v),G[v].push_back(u),M[{min(u,v),max(u,v)}]=i;
    	dfs(1,0);
    	for(int i=1;i<16;i++)for(int u=1;u<=n;u++)f[u][i]=f[f[u][i-1]][i-1];
    	memset(g,0x3f,sizeof g);
    	for(int u,v,w;m--;){
    		cin>>u>>v>>w;
    		if(d[u]<d[v])swap(u,v);
    		for(int i=15;~i;i--)if(d[f[u][i]]>=d[v])g[u][i]=min(g[u][i],w),u=f[u][i];
    		for(int i=15;~i;i--)if(f[u][i]!=f[v][i])g[u][i]=min(g[u][i],w),g[v][i]=min(g[v][i],w),u=f[u][i],v=f[v][i];
    		if(u!=v)g[u][0]=min(g[u][0],w),g[v][0]=min(g[v][0],w);
    	}for(int i=15;i;i--)for(int u=1;u<=n;u++)g[u][i-1]=min(g[u][i-1],g[u][i]),g[f[u][i-1]][i-1]=min(g[f[u][i-1]][i-1],g[u][i]);
    	for(int u=2;u<=n;u++)ans[M[{min(u,f[u][0]),max(u,f[u][0])}]]=g[u][0];
    	for(int i=1;i<n;i++)cout<<(ans[i]<0x3f3f3f3f?ans[i]:-1)<<'\n';
    	return 0;
    }
    
    • 1

    信息

    ID
    6798
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者