【luogu P4180 嚴格次小生成樹[BJWC2010]】 模板
阿新 • • 發佈:2018-11-06
題目連結:https://www.luogu.org/problemnew/show/P4180
這個題卡樹剖。記得開O2。
這個題inf要到1e18。
定理:次小生成樹和最小生成樹差距只有在一條邊上
非嚴格次小生成樹:列舉每一條不在最小生成樹上的邊,加入到最小生成樹中構成一個環。刪去這個環上的最大值。(此最大值有可能與加入生成樹中的邊相等,故為非嚴格次小生成樹。)重複此操作取min,得到次小生成樹。(基於kruskal實現。)
嚴格次小生成樹:與非嚴格次小生成樹類似,不同在於為了避免刪去環上的最大值等於加入生成樹中的邊,需要記錄次最大值。噁心點所在。
於是維護最大值和次小值又成了一道資料結構題。
樹剖:剖MST,查詢加進來的邊的兩端點編號 = =
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long #define lson l, mid, rt<<1 #define rson mid+1, r, rt<<1|1 using namespace std; const int maxn = 300010; const ll inf = 1e18; inline ll read() { char ch = getchar(); ll u = 0, f = 1; while (!isdigit(ch)) {if (ch == '-')f = -1; ch = getchar();} while (isdigit(ch)) {u = u * 10 + ch - 48; ch = getchar();}return u * f; } ll n, m, fa[maxn], deep[maxn], size[maxn], son[maxn], top[maxn], seg[maxn], rev[maxn], W[maxn], ans = inf, num; ll father[maxn], mstans, mstcnt; bool vis[maxn]; struct EDG{ ll u, v, w; }G[maxn];//mst struct edge{ ll to, next, len; }e[maxn<<2]; ll head[maxn], cnt; void add(ll u, ll v, ll w) { e[++cnt].len = w; e[cnt].next = head[u]; e[cnt].to = v; head[u] = cnt; e[++cnt].len = w; e[cnt].next = head[v]; e[cnt].to = u; head[v] = cnt; } //kruskal bool cmp(EDG a, EDG b) { return a.w < b.w; } ll find(ll x) { return father[x] == x ? x : father[x] = find(father[x]); } void init() { for(ll i = 1; i <= n; i++) father[i] = i; sort(G+1, G+1+m, cmp); } void kruskal() { init(); for(ll i = 1; i <= m; i++) { if(mstcnt == n-1) break; ll x = find(G[i].u), y = find(G[i].v); if(x != y) { mstans += G[i].w; mstcnt++; vis[i] = 1; add(G[i].u, G[i].v, G[i].w); father[x] = y; } } } //Segment_Tree bool maxcmp(ll a, ll b) { return a > b; } ll get_sec(ll a, ll b, ll c, ll d) { ll z[5] = {a, b, c, d}; sort(z, z+4, maxcmp); for(ll i = 1; i <= 3; i++) { if(z[i] != z[0]) return z[i]; } } struct Segment_Tree{ ll fir, sec; }tree[maxn<<2]; void PushUPfir(ll rt) { tree[rt].fir = max(tree[rt<<1].fir, tree[rt<<1|1].fir); } void PushUPsec(ll rt) { tree[rt].sec = get_sec(tree[rt<<1].fir, tree[rt<<1|1].fir, tree[rt<<1].sec, tree[rt<<1|1].sec); } void build(ll l, ll r, ll rt) { if(l == r) { tree[rt].fir = rev[l]; return; } ll mid = (l + r) >> 1; build(lson); build(rson); PushUPfir(rt); PushUPsec(rt); } Segment_Tree query(ll left, ll right, ll l, ll r, ll rt) { Segment_Tree max1 = {-inf,-inf}, max2 = {-inf,-inf}; if(left <= l && r <= right) { return (Segment_Tree){tree[rt].fir, tree[rt].sec}; } ll mid = (l + r) >> 1; if(left <= mid) max1 = query(left, right, lson); if(right > mid) max2 = query(left, right, rson); return (Segment_Tree) {max(max1.fir, max2.fir), get_sec(max1.fir, max1.sec, max2.fir, max2.sec)}; } //Tree_cut void dfs1(ll u, ll f, ll d) { ll maxson = -1; size[u] = 1; deep[u] = d; fa[u] = f; for(ll i = head[u]; i != -1; i = e[i].next) { ll v = e[i].to; if(f != v) { W[v] = W[u] + e[i].len; dfs1(v, u, d+1); size[u] += size[v]; if(maxson < size[v]) maxson = size[v], son[u] = v; } } } void dfs2(ll u, ll t) { seg[u] = ++num; rev[num] = W[u] - W[fa[u]];//字首和邊權上點權 //rev[num] = node[u]; top[u] = t; if(!son[u]) return; dfs2(son[u], t); for(ll i = head[u]; i != -1; i = e[i].next) { ll v = e[i].to; if(v == fa[u] || v == son[u]) continue; dfs2(v, v); } } ll LCA(ll x, ll y, ll d)//當前邊的權值 { ll res = -inf; while(top[x] != top[y]) { if(deep[top[x]] < deep[top[y]]) swap(x, y); Segment_Tree temp1 = query(seg[top[x]], seg[x], 1, n, 1); x = fa[top[x]]; res = max(res, (temp1.fir == d) ? temp1.sec : temp1.fir); } if(deep[x] < deep[y]) swap(x, y); Segment_Tree temp2 = query(seg[y] + 1, seg[x], 1, n, 1); return res = max(res, (temp2.fir == d) ? temp2.sec : temp2.fir); } int main() { memset(head, -1, sizeof(head)); n = read(); m = read(); //scanf("%lld%lld",&n,&m); for(ll i = 1; i <= m; i++) {G[i].u = read(); G[i].v = read(); G[i].w = read();}//scanf("%lld%lld%lld",&G[i].u,&G[i].v,&G[i].w); kruskal(); dfs1(1, 0, 1); dfs2(1, 1); build(1, n, 1); for(ll i = 1; i <= m; i++) { if(vis[i]) continue; ll temp = mstans + G[i].w - LCA(G[i].u, G[i].v, G[i].w); if(ans > temp && temp != mstans + G[i].w && temp > mstans) ans = temp; } printf("%lld",ans); return 0; }