【题目链接】
【思路要点】
- 对边的权值\(A\)排序,依次加入图中,用LinkCutTree维护权值\(B\)的最小生成树。
- 时间复杂度\(O(MLogN)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 50005 #define MAXM 100005 #define INF 1e9 struct querys {int x, y, a, b; }; struct info {int value, pos; }; struct LCT { struct Node { bool rev; int num, value, maxnum, pos; int father, child[2], up; }; Node a[MAXN+MAXM]; int home[MAXN+MAXM], size; private: void pushdown(int x) { if (!a[x].rev) return; a[x].rev = false; swap(a[x].child[0], a[x].child[1]); if (a[x].child[0]) a[a[x].child[0]].rev ^= true; if (a[x].child[1]) a[a[x].child[1]].rev ^= true; } void update(int x) { a[x].maxnum = a[x].value; a[x].pos = x; if (a[x].child[0] && a[a[x].child[0]].maxnum>a[x].maxnum) { a[x].maxnum = a[a[x].child[0]].maxnum; a[x].pos = a[a[x].child[0]].pos; } if (a[x].child[1] && a[a[x].child[1]].maxnum>a[x].maxnum) { a[x].maxnum = a[a[x].child[1]].maxnum; a[x].pos = a[a[x].child[1]].pos; } } bool get(int x) { pushdown(a[x].father); return a[a[x].father].child[1] == x; } void rotate(int x) { int f = a[x].father, g = a[f].father; pushdown(f); pushdown(x); bool tmp = get(x); a[x].up = a[f].up; a[f].up = 0; a[f].child[tmp] = a[x].child[tmp^1]; a[a[x].child[tmp^1]].father = f; a[f].father = x; a[x].child[tmp^1] = f; a[x].father = g; if (g) a[g].child[a[g].child[1] == f] = x; update(f); update(x); } void splay(int x) { pushdown(x); for (int f = a[x].father; (f = a[x].father); rotate(x)) if (a[f].father) rotate(get(x) == get(f)?f:x); } void access(int x) { splay(x); int tmp = a[x].child[1]; a[tmp].father = 0; a[tmp].up = x; a[x].child[1] = 0; update(x); for (int f = a[x].up; f; f = a[x].up) { splay(f); tmp = a[f].child[1]; a[tmp].father = 0; a[tmp].up = f; a[f].child[1] = x; a[x].father = f; a[x].up = 0; update(f); x = f; } } void reverse(int x) { access(x); splay(x); a[x].rev ^= true; } int find_root(int x) { access(x); splay(x); int now = x; while (a[now].child[0]) { now = a[now].child[0]; pushdown(now); } splay(now); return now; } void link(int x, int y) { reverse(x); splay(x); access(y); splay(y); a[y].child[1] = x; a[x].father = y; update(y); } void cut(int x, int y) { reverse(x); access(y); splay(y); a[x].father = 0; a[y].child[0] = 0; update(y); } int new_node(int num, int value) { size++; a[size].num = num; a[size].value = value; a[size].maxnum = value; a[size].pos = size; a[size].rev = false; a[size].father = 0; a[size].child[0] = 0; a[size].child[1] = 0; a[size].up = 0; return size; } public: void make_tree(int num, int value) { home[num] = new_node(num, value); } void insert(int x, int y) { link(home[x], home[y]); } void del(int x, int y) { cut(home[x], home[y]); } int get_root(int x) { return a[find_root(home[x])].num; } info query(int x, int y) { x = home[x]; y = home[y]; reverse(x); access(y); splay(y); info ans = (info){a[y].maxnum, a[a[y].pos].num}; return ans; } }; querys q[MAXM]; LCT T; bool cmp(querys x, querys y) { return x.a<y.a || (x.a == y.a && x.b<y.b); } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) scanf("%d%d%d%d", &q[i].x, &q[i].y, &q[i].a, &q[i].b); sort(q+1, q+1+m, cmp); int ans = INF; for (int i = 1; i <= n; i++) T.make_tree(i, 0); for (int i = 1; i <= m; i++) { T.make_tree(i+n, q[i].b); if (T.get_root(q[i].x) != T.get_root(q[i].y)) { T.insert(i+n, q[i].x); T.insert(i+n, q[i].y); } else { info tmp = T.query(q[i].x, q[i].y); if (tmp.value>q[i].b) { T.del(tmp.pos, q[tmp.pos-n].x); T.del(tmp.pos, q[tmp.pos-n].y); T.insert(i+n, q[i].x); T.insert(i+n, q[i].y); } } if (T.get_root(1) == T.get_root(n)) ans = min(ans, q[i].a+T.query(1, n).value); } if (ans == INF) printf("-1\n"); else printf("%d\n", ans); return 0; }