分析
这题我们仔细分析一下,每次断掉一条树边其实就是将一棵树分成两部分,然后走一条边权最短的,端点分别在两个区域的就行了。那么转化一下题意,其实就是对于每一条树边,我们要求的就是覆盖到这条边的所有给出的m条边中边权最小的是多少。转化完之后实际上这道题就变成了链上取min然后单点查询了(将一条边边权给下放到更深的那个点的点权),然后直接上树剖+线段树就好了。复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n),据说也可以不用树剖,直接启发式合并,复杂度是 O ( n log n ) O(n\log n) O(nlogn)的,但我可能不太会,就写了树剖。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-48,ch=getchar();
x*=f;
}
inline void Setfile(string Str="") {
if(Str=="")
return;
freopen((Str+".in").c_str(),"r",stdin);
freopen((Str+".out").c_str(),"w",stdout);
}
struct Edge {
int u,v,w;
Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
inline bool operator < (const Edge &rhs) const {
return w<rhs.w;
}
};
const int maxn=100005;
vector<Edge>edges;
vector<int>G[maxn];
int n,q,fa[maxn][19],hson[maxn],sz[maxn],dfn[maxn],val[maxn],dep[maxn],clk,topx[maxn],m,fr[maxn],to[maxn],bel[maxn];
inline void dfs(int u,int fa) {
bel[u]=1;
for(int i=0;i<(int)G[u].size();++i) {
int v=G[u][i];
if(v==fa)
continue;
dfs(v,u);
}
}
inline void prework(int u=1,int p=0) {
sz[u]=1;
for(int i=1;i<19;++i)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=0;i<(int)G[u].size();++i) {
int v=G[u][i];
if(v==p)
continue;
dep[v]=dep[u]+1,fa[v][0]=u,prework(v,u),sz[u]+=sz[v];
if(!hson[u]||sz[hson[u]]<sz[v])
hson[u]=v;
}
}
inline void fstwork(int u=1,int tp=1) {
dfn[u]=++clk;
topx[u]=tp;
if(!hson[u])
return;
fstwork(hson[u],tp);
for(int i=0;i<(int)G[u].size();++i) {
int v=G[u][i];
if(v==fa[u][0]||v==hson[u])
continue;
fstwork(v,v);
}
}
namespace line {
int tr[maxn<<2],lz[maxn<<2];
inline void build(int o,int l,int r) {
lz[o]=tr[o]=2e9;
if(l==r)
return;
int mid=(l+r)>>1;
build(o<<1,l,mid),build(o<<1|1,mid+1,r);
}
inline void modify(int o,int d) {
tr[o]=min(tr[o],d),lz[o]=min(lz[o],d);
}
inline void pushdown(int o) {
if(lz[o]<2e9)
modify(o<<1,lz[o]),modify(o<<1|1,lz[o]),lz[o]=2e9;
}
inline void update(int o,int l,int r,int ql,int qr,int d) {
if(ql<=l&&r<=qr) {
modify(o,d);
return;
}
int mid=(l+r)>>1;
if(ql<=mid)
update(o<<1,l,mid,ql,qr,d);
if(qr>mid)
update(o<<1|1,mid+1,r,ql,qr,d);
tr[o]=min(tr[o<<1],tr[o<<1|1]);
}
inline int query(int o,int l,int r,int p) {
if(l==r)
return tr[o];
pushdown(o);
int mid=(l+r)>>1;
if(p<=mid)
return query(o<<1,l,mid,p);
else
return query(o<<1|1,mid+1,r,p);
}
inline int lca(int x,int y) {
while(topx[x]!=topx[y]) {
if(dep[topx[x]]>dep[topx[y]])
x=fa[topx[x]][0];
else
y=fa[topx[y]][0];
}
return dep[x]<dep[y]?x:y;
}
inline void upd(int x,int y,int d) {
while(topx[x]!=topx[y])
update(1,1,n,dfn[topx[x]],dfn[x],d),x=fa[topx[x]][0];
update(1,1,n,dfn[y],dfn[x],d);
}
inline int up(int x,int d) {
for(int i=18;~i;--i)
if(d>>i&1)
x=fa[x][i];
return x;
}
inline void modi(int x,int y,int d) {
int l=lca(x,y),u=up(x,dep[x]-dep[l]-1),v=up(y,dep[y]-dep[l]-1);
if(x!=l)
upd(x,u,d);
if(y!=l)
upd(y,v,d);
}
inline void solve() {
build(1,1,n);
for(int i=0;i<m;++i)
modi(edges[i].u,edges[i].v,edges[i].w);
for(int i=1;i<n;++i) {
int ans=dep[fr[i]]<dep[to[i]]?query(1,1,n,dfn[to[i]]):query(1,1,n,dfn[fr[i]]);
printf("%d\n",ans>1e9?-1:ans);
}
}
}
int main() {
Setfile();
read(n),read(m);
for(int i=1,x,y;i<n;++i)
read(x),read(y),G[x].push_back(y),G[y].push_back(x),fr[i]=x,to[i]=y;
for(int i=1,x,y,z;i<=m;++i)
read(x),read(y),read(z),edges.push_back(Edge(x,y,z));
prework(),fstwork();
line::solve();
return 0;
}