1. 程式人生 > >[BZOJ5279][Usaco2018 Open]Disruption(樹剖+線段樹)

[BZOJ5279][Usaco2018 Open]Disruption(樹剖+線段樹)

題目傳送門

分析

  這題我們仔細分析一下,每次斷掉一條樹邊其實就是將一棵樹分成兩部分,然後走一條邊權最短的,端點分別在兩個區域的就行了。那麼轉化一下題意,其實就是對於每一條樹邊,我們要求的就是覆蓋到這條邊的所有給出的m條邊中邊權最小的是多少。轉化完之後實際上這道題就變成了鏈上取min然後單點查詢了(將一條邊邊權給下放到更深的那個點的點權),然後直接上樹剖+線段樹就好了。複雜度O(nlog2n)O(n\log^2 n),據說也可以不用樹剖,直接啟發式合併,複雜度是O(nlogn)O(n\log n)的,但我可能不太會,就寫了樹剖。

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; }