cf160D. Edges in MST(最小生成樹 橋)
阿新 • • 發佈:2018-11-11
題意
給出一棵樹,確定每條邊狀態: 一定在MST上 / 可能在MST上 / 不可能在MST上
\(n \leqslant 10^5, m \leqslant 10^5\)
Sol
MST表示最小生成樹
表示只能想到\(nlog^2n\)的做法:先求出MST。然後列舉剩下的邊,如果權值出現在形成的環上,那麼該邊和MST上的邊都是可能出現,如果權值大於環上最大值,那麼該邊不可能在MST上。沒有被標記過的邊一定在MST上。
樹剖+主席樹維護一下。。
標算好神仙啊。
結論:將任意兩個MST上的邊排序後,得到的序列是相同的
自己xjbYY的證明:
反證法。
若不滿足條件,則兩個序列中一定存在四個位置
\(x_1, y_1\)
\(x_2, y_2\)
滿足\(x_1 < x_2\)且\(y_1 > y_2\)。(如果只有一個不同的話權值大的不會成為MST)
那麼把\(x_1\)加入到第二個MST中,同時刪去環上最大的邊,會得到一個權值更小的MST。
哎,自己還想到這裡了,不過立馬就否決了。。
首先排序,對權值相同的邊一起考慮。如果當前邊所連的聯通塊已經被合併,那麼該邊一定不在MST上。這樣就解決了第三種情況
考慮剩下的邊,要麼一定在MST上,要麼可能在MST上。
如果一定在MST上,顯然斷開它之後會形成兩個聯通塊。這與“橋”的定義相同!所以tarjan一遍求出所有橋就行了。
如果每次都tarjan的話顯然會T飛,因此我們把在一個聯通塊內的點縮起來就行了
#include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second using namespace std; const int MAXN = 2e5 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N, M; vector<Pair> v[MAXN]; struct Edge { int u, v, w, f, id; bool operator < (const Edge &rhs) const { return w < rhs.w; } }E[MAXN]; int dfn[MAXN], low[MAXN], tot, fa[MAXN], ans[MAXN]; void tarjan(int x, int fa) {//這裡的fa表示邊的編號 dfn[x] = low[x] = ++tot; for(int i = 0, to, id; i < v[x].size(); i++) { if((id = v[x][i].se) == fa) continue; to = v[x][i].fi; if(!dfn[to]) { tarjan(to, id), low[x] = min(low[x], low[to]); if(low[to] > dfn[x]) E[id].f = 2; } else low[x] = min(low[x], dfn[to]); } } int find(int x) { return x == fa[x] ? fa[x] : fa[x] = find(fa[x]); } int main() { N = read(), M = read(); for(int i = 1; i <= N; i++) fa[i] = i; for(int i = 1; i <= M; i++) { int x = read(), y = read(), z = read(); E[i] = (Edge) {x, y, z, 0, i}; } sort(E + 1, E + M + 1); int nxt; for(int i = 1; i <= M; i = nxt + 1) { nxt = i + 1; for(; E[i].w == E[nxt].w; nxt++); nxt--; for(int j = i; j <= nxt; j++) { int x = find(E[j].u), y = find(E[j].v); if(x == y) continue; v[x].push_back(MP(y, j)); v[y].push_back(MP(x, j)); E[j].f = 1;//maybe } for(int j = i; j <= nxt; j++) { int x = find(E[j].u), y = find(E[j].v); if(x == y || dfn[x]) continue; tarjan(x, -1); } for(int j = i; j <= nxt; j++) { int x = find(E[j].u), y = find(E[j].v); if(x == y) continue; v[x].clear(); v[y].clear(); dfn[x] = 0; dfn[y] = 0; fa[x] = y; } } for(int i = 1; i <= M; i++) ans[E[i].id] = E[i].f; for(int i = 1; i <= M; i++) { if(ans[i] == 0) puts("none"); else if(ans[i] == 1) puts("at least one"); else puts("any"); } return 0; } /* */