BZOJ 3669 [Noi2014]魔法森林 | LCT

Posted 胡小兔的OI博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3669 [Noi2014]魔法森林 | LCT相关的知识,希望对你有一定的参考价值。

迷啊……调了一下午……
为什么我把splay时的update方式改成“splay最后再upt(u)一下”就不RE了……
求大神解答……?

题目链接

BZOJ 3669

题解

将边按照a排序,然后从小到大枚举,加入图中。

在图中用lct维护一棵两点之间b最大值尽量小的生成树。

当加入一条边(u, v)时:
如果(u, v)不连通,则直接加入这条边
如果(u, v)连通且它们间路径上的b最大值大于当前边的b,则删除路径上b最大的边,然后加入当前边。
否则这条边没用,啥也不干。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cstdlib>
using namespace std;
typedef unsigned long long ll;
#define enter putchar('\n')
#define space putchar(' ')
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c > '9' || c < '0')
    if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
    x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
const int N = 150005, M = 100005, INF = 0x3f3f3f3f;
int n, m, pcnt, ans = INF;
int fa[N], ls[N], rs[N], val[N], num[N]; //val和num存的都是边的编号
bool rev[N];
struct Edge {
    int u, v, a, b, p;
    bool operator < (const Edge &obj) const{
        return a == obj.a ? b < obj.b : a < obj.a;
    }
} e[M];
#define which(u) (ls[fa[u]] == (u))
#define isroot(u) (!fa[u] || (ls[fa[u]] != (u) && rs[fa[u]] != (u)))
int Max(int A, int B){
    return e[A].b > e[B].b ? A : B;
}
void upt(int u){
    val[u] = Max(Max(val[ls[u]], val[rs[u]]), num[u]);
}
void pushdown(int u){
    if(!rev[u]) return;
    swap(ls[u], rs[u]);
    if(ls[u]) rev[ls[u]] ^= 1;
    if(rs[u]) rev[rs[u]] ^= 1;
    rev[u] = 0;
}
void rotate(int u){
    int v = fa[u], w = fa[v], b = which(u) ? rs[u] : ls[u];
    if(!isroot(v)) (which(v) ? ls[w] : rs[w]) = u;
    which(u) ? (ls[v] = b, rs[u] = v) : (rs[v] = b, ls[u] = v);
    fa[u] = w, fa[v] = u;
    if(b) fa[b] = v;
    upt(v);
}
void splay(int u){
    static int stk[N], top;
    stk[top = 1] = u;
    while(!isroot(stk[top])) stk[top + 1] = fa[stk[top]], top++;
    while(top) pushdown(stk[top--]);
    while(!isroot(u)){
        if(!isroot(fa[u])){
            if(which(u) == which(fa[u])) rotate(fa[u]);
            else rotate(u);
        }
        rotate(u);
    }
    upt(u);
}
void access(int u){
    int v = 0;
    while(u){
        splay(u);
        rs[u] = v;
        v = u;
        u = fa[u];
    }
}
void makeroot(int u){
    access(u);
    splay(u);
    rev[u] ^= 1;
}
int findroot(int u){
    access(u);
    splay(u);
    while(pushdown(u), ls[u]) u = ls[u];
    splay(u);
    return u;
}
void link(int u, int v){
    makeroot(u);
    fa[u] = v;
}
void cut(int u, int v){
    makeroot(u);
    access(v);
    splay(v);
    ls[v] = fa[u] = 0;
    upt(v);
}
void insert_edge(int i){
    e[i].p = ++pcnt;
    num[e[i].p] = val[e[i].p] = i;
    link(e[i].u, e[i].p);
    link(e[i].v, e[i].p);
}
void erase_edge(int i){
    cut(e[i].u, e[i].p);
    cut(e[i].v, e[i].p);
}
int query(int u, int v){
    makeroot(u);
    access(v);
    splay(v);
    return val[v];
}

int main(){
    read(n), read(m), pcnt = n;
    for(int i = 1; i <= m; i++)
        read(e[i].u), read(e[i].v), read(e[i].a), read(e[i].b);
    sort(e + 1, e + m + 1);
    for(int i = 1; i <= m; i++){
        if(findroot(e[i].u) != findroot(e[i].v)) insert_edge(i);
        else{
            int maxe = query(e[i].u, e[i].v);
            if(e[maxe].b > e[i].b)
                erase_edge(maxe), insert_edge(i);
        }
        if(findroot(1) == findroot(n))
            ans = min(ans, e[i].a + e[query(1, n)].b);
    }
    write(ans < INF ? ans : -1), enter;
    return 0;
}

以上是关于BZOJ 3669 [Noi2014]魔法森林 | LCT的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ3669][Noi2014]魔法森林

bzoj3669: [Noi2014]魔法森林

bzoj 3669 [Noi2014]魔法森林

bzoj 3669: [Noi2014]魔法森林

BZOJ3669[Noi2014]魔法森林 LCT

bzoj3669[Noi2014]魔法森林