[BZOJ5279][Usaco2018 Open]Disruption(樹剖+線段樹)
阿新 • • 發佈:2018-12-16
分析
這題我們仔細分析一下,每次斷掉一條樹邊其實就是將一棵樹分成兩部分,然後走一條邊權最短的,端點分別在兩個區域的就行了。那麼轉化一下題意,其實就是對於每一條樹邊,我們要求的就是覆蓋到這條邊的所有給出的m條邊中邊權最小的是多少。轉化完之後實際上這道題就變成了鏈上取min然後單點查詢了(將一條邊邊權給下放到更深的那個點的點權),然後直接上樹剖+線段樹就好了。複雜度,據說也可以不用樹剖,直接啟發式合併,複雜度是的,但我可能不太會,就寫了樹剖。
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;
}