将 最小生成树 构建出来, 将没加入最小生成树 的边称为 “虚边”,
假设有一条 “虚边” 为 , 则 在树上的路径上的边可能被替换, 称路径上的边被覆盖 .
- 先考虑 树边 的答案怎么求,
当一条 树边 没有被任何 “虚边” 覆盖时, 其答案显然为 ,
当一条 树边 被若干 “虚边” 覆盖时, 为了不被取代, 只能取其中最小的 “虚边” 权值 . - 在考虑 非树边 的答案怎么求,
非树边 为了可能成为生成树中的边, 且权值需要尽可能大, 所以答案直接取 路径中树边的最大权值 .
同上 .
- 路径中树边的最大权值 可以使用 倍增 维护,
- 路径覆盖使用 树上差分 配合 重链剖分 和
std::multiset<int>
维护 . - 往上跳重链维护差分值时要注意 !!! 由于是将每条边压到这条边下面的点, 所以最后一步差分的起点位置要加 .
的惨痛经历 .
#include<bits/stdc++.h>
#define reg register
#define pb push_back
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 2e6 + 5;
int N;
int M;
int num0;
int F[maxn];
int head[maxn];
struct Edge{ int nxt, to, w, id; } edge[maxn<<1];
void Add(int from, int to, int w, int id){ edge[++ num0] = (Edge){ head[from], to, w, id }; head[from] = num0; }
int Find(int x){ return F[x]==x?x:F[x]=Find(F[x]); }
struct EDGE{ int u, v, w, id; } E[maxn];
std::multiset <int> st;
std::multiset <int>::iterator it;
std::vector <int> B[maxn];
std::vector <EDGE> A;
bool cmp_1(EDGE a, EDGE b){ return a.w < b.w; }
void Krus(){
std::sort(E+1, E+M+1, cmp_1);
int cnt = 0;
for(reg int i = 1; i <= N; i ++) F[i] = i;
for(reg int i = 1; i <= M; i ++){
int a = Find(E[i].u), b = Find(E[i].v);
if(a == b) A.pb(E[i]);
else{
F[b] = a;
Add(E[i].u, E[i].v, E[i].w, E[i].id), Add(E[i].v, E[i].u, E[i].w, E[i].id);
if((++ cnt) >= N-1){
for(reg int j = i+1; j <= M; j ++) A.pb(E[j]);
return ;
}
}
}
}
int dep[maxn];
int Ans[maxn];
int Fk[100005][21];
int Mk[100005][21];
int Fa_edge[maxn];
int size[maxn];
int max_son[maxn];
int Fa[maxn];
int max_w[maxn];
void DFS_1(int k, int fa){
dep[k] = dep[fa] + 1;
size[k] = 1; max_son[k] = 0, max_w[k] = 0;
Fa[k] = fa;
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
if(to == fa) continue ;
DFS_1(to, k); size[k] += size[to];
Fa_edge[to] = edge[i].id;
if(size[to] > max_w[k]) max_w[k] = size[to], max_son[k] = to;
}
}
int dfn_tim;
int Mp[maxn];
int dfn[maxn];
int top[maxn];
void DFS_2(int k, int fa){
top[k] = fa;
dfn[k] = ++ dfn_tim; Mp[dfn[k]] = k;
if(max_son[k]) DFS_2(max_son[k], fa);
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
if(dfn[to]) continue ;
DFS_2(to, to);
}
}
void Modify_P(int x, int y, int z){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
B[dfn[top[x]]].pb(z), B[dfn[x]+1].pb(-z);
x = Fa[top[x]];
}
if(dfn[x] > dfn[y]) std::swap(x, y);
B[dfn[x]+1].pb(z), B[dfn[y]+1].pb(-z);
}
void DFS_0(int k, int fa){
for(reg int i = 1; i <= 20; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
for(reg int i = 1; i <= 20; i ++) Mk[k][i] = std::max(Mk[k][i-1], Mk[Fk[k][i-1]][i-1]);
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
if(to == fa) continue ;
Fk[to][0] = k, Mk[to][0] = edge[i].w;
DFS_0(to, k);
}
}
int Mca(int a, int b){
if(dep[a] < dep[b]) std::swap(a, b);
int s = 0;
for(reg int i = 20; i >= 0; i --)
if(dep[Fk[a][i]] >= dep[b]) s = std::max(s, Mk[a][i]), a = Fk[a][i];
if(a == b) return s;
for(reg int i = 20; i >= 0; i --)
if(Fk[a][i] != Fk[b][i]){
s = std::max(s, Mk[a][i]), s = std::max(s, Mk[b][i]);
a = Fk[a][i], b = Fk[b][i];
}
s = std::max(s, Mk[a][0]); s = std::max(s, Mk[b][0]);
return s;
}
int main(){
N = read(), M = read();
for(reg int i = 1; i <= M; i ++) E[i].u = read(), E[i].v = read(), E[i].w = read()+1, E[i].id = i;
Krus();
DFS_0(1, 0); DFS_1(1, 1); DFS_2(1, 1);
int len = A.size();
for(reg int i = 0; i < len; i ++){
int a = A[i].u, b = A[i].v;
Ans[A[i].id] = Mca(a, b);
Modify_P(a, b, A[i].w);
}
for(reg int i = 1; i <= N; i ++){
int x = Mp[i], len = B[i].size();
for(reg int j = 0; j < len; j ++){
if(B[i][j] > 0) st.insert(B[i][j]);
else st.erase(st.find(-B[i][j]));
}
if(st.empty()) Ans[Fa_edge[x]] = 1e9 + 1;
else Ans[Fa_edge[x]] = *st.begin();
}
for(reg int i = 1; i <= M; i ++) printf("%d
", Ans[i]-1); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! edge.w plus 1
return 0;
}