ABC301Ex 题解

· · 题解

这怎么放到 Ex 的啊 /fn

【简要题意】

**【题解】** 经典结论是 $u \to v$ 的最小瓶颈路等于最小生成树上 $u,v$ 之间的最大边权。 建最小生成树,考虑第 $i$ 条边的位置,如果它根本不在 $u,v$ 的路径上,或者小于 $u,v$ 路径上的 $\max$,那么对答案肯定没有影响。否则,我们需要找到这条边边权 $+1$ 后新的最小生成树,其实就是断开边 $i$ 后连接两个连通块的最小边权。令边 $i$ 为 $(x,y)$ 且 $dep_x > dep_y$,注意新边 $(x',y')$ 需要满足 $x'$ 在 $x$ 子树内且 $y'$ 不在 $x$ 的子树内,转化为 dfn 序后是**二维数点**模型。由于 $\min$ 没有可减性,我们用树套树维护。 找到新的最小生成树后,只需要求出新的最小生成树上 $u,v$ 之间的最大边,拆成 $(u,x'),(x',y'),(y',v)$ 三段路径在原树上求 $\max$ 即可。 复杂度瓶颈在树套树,时空复杂度均为 $\mathcal O(n \log^2 n)$。 事实上,由于每次二维数点一定有一维形如 $[1,x]$ 或 $[x,n]$,可以正着倒着各做一遍扫描线,线段树维护另一维的 $\min$ 即可做到一只 $\log$。 两只 $\log$ 的实现虽然代码略长($\text{4.51KB}$),但是基本没有细节,调试较为简单。 ```cpp #include <bits/stdc++.h> using namespace std; const int N = 2e5+5; int top[N],son[N],fa[N],siz[N],dfn[N],dep[N],rt[N*40],tot,ti,tu,tv,u,a,v,q,p[N],mx[N][22],ans[N],f[N][22],val[N],vis[N],n,m,au[N],av[N],aw[N]; int t[N*300],ls[N*300],rs[N*300]; int cmp(int x,int y){return aw[x] < aw[y] ? x : y;} struct ges{ struct seg{ void upd(int &s,int l,int r,int x,int k){ if(!s) s = ++tot; if(l == r) return t[s] = cmp(t[s],k),void(); int mid = (l + r) / 2; if(x <= mid) upd(ls[s],l,mid,x,k); else upd(rs[s],mid+1,r,x,k); t[s] = cmp(t[ls[s]],t[rs[s]]); }int qry(int s,int l,int r,int ql,int qr){ if(ql <= l && r <= qr) return t[s]; int mid = (l + r) / 2,ans = 0; if(ql <= mid) ans = cmp(ans,qry(ls[s],l,mid,ql,qr)); if(qr > mid) ans = cmp(ans,qry(rs[s],mid+1,r,ql,qr)); return ans; } }sg; void upd(int s,int l,int r,int x,int y,int k){ sg.upd(rt[s],1,n,y,k); int mid = (l + r) / 2; if(l == r) return ; if(x <= mid) upd(s*2,l,mid,x,y,k); else upd(s*2+1,mid+1,r,x,y,k); }int qry(int s,int l,int r,int ql,int qr,int tl,int tr){ if(ql > qr || tl > tr) return 0; if(ql <= l && r <= qr) return sg.qry(rt[s],1,n,tl,tr); int mid = (l + r) / 2,ans = 0; if(ql <= mid) ans = cmp(ans,qry(s*2,l,mid,ql,qr,tl,tr)); if(qr > mid) ans = cmp(ans,qry(s*2+1,mid+1,r,ql,qr,tl,tr)); return ans; } }seg; struct dsu{ int fa[N]; int fd(int x){return x == fa[x] ? x : fa[x] = fd(fa[x]);} void init(){for(int i = 1;i <= n;i ++) fa[i] = i;} void mg(int x,int y){x = fd(x),y = fd(y),fa[x] = y;} }d; vector<pair<int,int>> g[N]; void dfs1(int u,int ft){ fa[u] = ft,dep[u] = dep[ft] + 1,siz[u] = 1,f[u][0] = ft,mx[u][0] = val[u]; for(int i = 1;i <= __lg(dep[u]);i ++) f[u][i] = f[f[u][i-1]][i-1],mx[u][i] = max(mx[u][i-1],mx[f[u][i-1]][i-1]); for(auto [v,w] : g[u]) if(v != ft) if(val[v] = w,dfs1(v,u),siz[u] += siz[v],siz[v] > siz[son[u]]) son[u] = v; }void dfs2(int u,int tp){ top[u] = tp,dfn[u] = ++ti; if(son[u]) dfs2(son[u],tp); for(auto [v,w] : g[u]) if(v != son[u] && v != fa[u]) dfs2(v,v); }int qrymax(int u,int v){ if(dep[u] < dep[v]) swap(u,v); int ans = 0; for(int i = __lg(dep[u]);i >= 0;i --) if(dep[f[u][i]] >= dep[v]) ans = max(ans,mx[u][i]),u = f[u][i]; return ans; }int lca(int u,int v){ while(top[u] != top[v]) if(dep[top[u]] > dep[top[v]]) u = fa[top[u]]; else v = fa[top[v]]; return dep[u] < dep[v] ? u : v; }bool ck(int u,int v,int x,int y){ int fx = 0,fy = 0; auto kc = [&](int l,int r,int x){return l <= x && x <= r;}; while(top[u] != top[v]){ if(dep[top[u]] < dep[top[v]]) swap(u,v); fx |= kc(dfn[top[u]],dfn[u],dfn[x]),fy |= kc(dfn[top[u]],dfn[u],dfn[y]),u = fa[top[u]]; }if(dfn[u] > dfn[v]) swap(u,v); fx |= kc(dfn[u],dfn[v],dfn[x]),fy |= kc(dfn[u],dfn[v],dfn[y]); return fx && fy; }int qpath(int u,int v){int d = lca(u,v); return max(qrymax(u,d),qrymax(v,d));} int main(){ ios::sync_with_stdio(0),cin.tie(0); cin >> n >> m; d.init(); aw[0] = 1e9; for(int i = 1;i <= m;i ++) cin >> au[i] >> av[i] >> aw[i],p[i] = i; sort(p + 1,p + m + 1,[&](int x,int y){return aw[x] < aw[y];}); auto add = [&](int x,int y,int w){g[x].emplace_back(y,w),g[y].emplace_back(x,w);}; for(int i = 1;i <= m;i ++) if(u = d.fd(au[p[i]]),v = d.fd(av[p[i]]),u != v) vis[p[i]] = 1,d.mg(u,v),add(au[p[i]],av[p[i]],aw[p[i]]); dfs1(1,0),dfs2(1,1); for(int i = 1;i <= m;i ++) if(!vis[i]) seg.upd(1,1,n,dfn[au[i]],dfn[av[i]],i),seg.upd(1,1,n,dfn[av[i]],dfn[au[i]],i); for(cin >> q;q --;){ cin >> a >> u >> v,tu = au[a],tv = av[a]; if(dep[tu] < dep[tv]) swap(tu,tv); if(!ck(u,v,tu,tv)) {cout << "0\n"; continue;} int d = lca(u,v),mx = max(qrymax(u,d),qrymax(v,d)); if(aw[a] != mx) {cout << "0\n"; continue;} int k = cmp(seg.qry(1,1,n,dfn[tu],dfn[tu] + siz[tu] - 1,1,dfn[tu] - 1), seg.qry(1,1,n,dfn[tu],dfn[tu] + siz[tu] - 1,dfn[tu] + siz[tu],n)); if(aw[k] < mx) cout << "0\n"; else if(aw[k] > mx) cout << "1\n"; else{ auto ck = [&](int u,int v){return dfn[u] <= dfn[v] && dfn[v] <= dfn[u] + siz[u] - 1;}; int ru = au[k],rv = av[k]; if(!ck(tu,ru)) swap(ru,rv); if(min(qpath(u,ru),qpath(v,rv)) <= aw[a]) cout << "0\n"; else cout << "1\n"; } } } ```