【BZOJ 3669】【NOI 2014】魔法森林 LCT+枚举边
$LCT+枚举$ 复习一下$LCT$模板。
先以$Ai$为关键字$sort$,然后$Ai$从小到大枚举每条边,看能否构成环,构不成则加边,构成则判断,判断过了就切断$Bi$最大的边。
我的边是编号为$i+n$的点,忘了这点调了好久$QAQ$ $sosad$
#include<cstdio> #include<cstring> #include<algorithm> #define N 150003 #define read(x) x=getint() using namespace std; inline int getint() {int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh;} struct nodeE {int a, b, x, y;} E[N]; struct node *null; struct node { node *ch[2], *fa; int d, pos; short rev; bool pl() {return fa->ch[1] == this;} bool check() {return fa == null || (fa->ch[0] != this && fa->ch[1] != this);} void push() {if (rev) {rev = 0; swap(ch[0], ch[1]); ch[0]->rev ^= 1; ch[1]->rev ^= 1;}} void count() { pos = d; if (E[ch[0]->pos].b > E[pos].b) pos = ch[0]->pos; if (E[ch[1]->pos].b > E[pos].b) pos = ch[1]->pos; } void setc(node *r, bool c) {ch[c] = r; r->fa = this;} } *rt[N]; node pool[N]; int n, m, tot = 0; namespace LCT { int ans = 0x7fffffff; bool cmp(nodeE X, nodeE Y) {return X.a < Y.a;} node *newnode(int num = 0) { node *t = &pool[++tot]; t->ch[0] = t->ch[1] = t->fa = null; t->d = t->pos = num; t->rev = 0; return t; } void Build() { null = &pool[0]; null->ch[0] = null->ch[1] = null->fa = null; null->d = null->pos = null->rev = 0; read(n); read(m); for(int i = 1; i <= m; ++i) {read(E[i].x); read(E[i].y); read(E[i].a); read(E[i].b);} sort(E + 1, E + m + 1, cmp); for(int i = 1; i <= n; ++i) rt[i] = newnode(); for(int i = 1; i <= m; ++i) rt[n + i] = newnode(i); E[0].b = 0; } void rotate(node *r) { node *f = r->fa; bool c = r->pl(); if (f->check()) r->fa = f->fa; else f->fa->setc(r, f->pl()); f->setc(r->ch[!c], c); r->setc(f, !c); f->count(); } void update(node *r) {if (!r->check()) update(r->fa); r->push();} void splay(node *r) { update(r); for(; !r->check(); rotate(r)) if (!r->fa->check()) rotate(r->pl() == r->fa->pl() ? r->fa : r); r->count(); } node *access(node *r) {node *y = null; for(; r != null; y = r, r = r->fa) {splay(r); r->ch[1] = y;} return y;} void changert(node *r) {access(r)->rev ^= 1; splay(r);} void link(node *r, node *t) {changert(r); r->fa = t;} void cut(node *r, node *t) {changert(r); access(t); splay(t); t->ch[0]->fa = null; t->ch[0] = null;} node *findrt(node *r) {access(r); splay(r); while(r->ch[0] != null) r = r->ch[0]; return r;} int ask(node *r, node *t) {changert(r); access(t); splay(t); return t->pos;} void work(int u, int v, int edge) { if (findrt(rt[u]) == findrt(rt[v])) { int k = ask(rt[u], rt[v]); if (E[k].b > E[edge - n].b) { cut(rt[u], rt[k + n]); cut(rt[v], rt[k + n]); link(rt[u], rt[edge]); link(rt[v], rt[edge]); } } else { link(rt[u], rt[edge]); link(rt[v], rt[edge]); } if (findrt(rt[1]) == findrt(rt[n])) ans = min(ans, E[edge - n].a + E[ask(rt[1], rt[n])].b); } void AC() {printf("%d\n", ans == 0x7fffffff ? -1 : ans);} } int main() { LCT::Build(); for(int i = 1; i <= m ;++i) LCT::work(E[i].x, E[i].y, i + n); LCT::AC(); return 0; }
我的代码就是一堵墙,让$300$行的$LinkCutTree$在压行大法前颤抖吧~~~
NOI 2017 Bless All