bzoj3669

http://www.lydsy.com/JudgeOnline/problem.php?id=3669

lct维护最小生成树 裸题 最小的边一定在最小生成树上 如果我们能用其他边调整 那么我们从能调整的边中选一条 因为肯定有一条比替换掉的小 那么就矛盾了

#include<bits/stdc++.h>
using namespace std;
const int N = 400010;
struct edge {
    int a, b, u, v;
} e[N];
int n, m, ans = 1 << 29;
int pos[N], father[N], tag[N], fa[N], child[N][2], st[N];
namespace get
{   
    void Init() { for(int i = 1; i <= n + m; ++i) pos[i] = father[i] = i; }
    int find(int x) { return x == father[x] ? x : father[x] = find(father[x]); }
    void connect(int x, int y)
    {
        int u = find(x), v = find(y);
        if(u == v) return;
        father[u] = v;
    }
} using namespace get;
namespace lct
{   
    bool cp(edge i, edge j) { return i.a < j.a; }    
    int c(int x) { return x > n ? x - n : 0; }
    void update(int x)
    {
        pos[x] = x;
        if(e[c(pos[child[x][0]])].b > e[c(pos[x])].b) pos[x] = pos[child[x][0]];
        if(e[c(pos[child[x][1]])].b > e[c(pos[x])].b) pos[x] = pos[child[x][1]];
    }   
    bool isroot(int x) { return !fa[x] || (child[fa[x]][0] != x && child[fa[x]][1] != x); }
    void pushdown(int x)
    {
        if(!tag[x]) return;
        tag[child[x][0]] ^= 1; tag[child[x][1]] ^= 1;
        swap(child[x][0], child[x][1]);
        tag[x] ^= 1;
    }
    void zig(int x)
    {
        int y = fa[x]; fa[x] = fa[y];
        if(!isroot(y)) child[fa[x]][child[fa[x]][1] == y] = x;
        child[y][0] = child[x][1]; fa[child[x][1]] = y;
        fa[y] = x; child[x][1] = y;
        update(y); update(x);
    }
    void zag(int x)
    {
        int y = fa[x]; fa[x] = fa[y];
        if(!isroot(y)) child[fa[x]][child[fa[x]][1] == y] = x;
        child[y][1] = child[x][0]; fa[child[x][0]] = y;
        fa[y] = x; child[x][0] = y;
        update(y); update(x);
    }
    void splay(int x)
    {
        int top = 0; st[++top] = x;
        for(int now = x; !isroot(now); now = fa[now]) st[++top] = fa[now];
        for(int i = top; i; --i) pushdown(st[i]);
        while(!isroot(x))
        {
            int y = fa[x], z = fa[y];
            if(isroot(y)) { child[y][0] == x ? zig(x) : zag(x); break; }
            else if(child[y][0] == x && child[z][0] == y) { zig(y); zig(x); }
            else if(child[y][1] == x && child[z][1] == y) { zag(y); zag(x); }
            else if(child[y][1] == x && child[z][0] == y) { zag(x); zig(x); }
            else if(child[y][0] == x && child[z][1] == y) { zig(x); zag(x); }   
        }
    }
    void access(int x)
    {
        for(int t = 0; x; t = x, x = fa[x])
        {
            splay(x); child[x][1] = t; update(x);
        }
    }
    void rever(int x)
    {
        access(x); splay(x); tag[x] ^= 1; 
    }
    int findr(int x)
    {
        access(x); splay(x); 
        for(; child[x][0]; x = child[x][0]);
        return x;
    }
    void link(int u, int v)
    {
        rever(u); fa[u] = v;
    }
    void cut(int u, int v)
    {
        rever(u); access(v); splay(v); child[v][0] = fa[u] = 0; update(v); update(u);
    }
    void add(int i)
    {
        int u = e[i].u, v = e[i].v;
//      printf("findu=%d findv=%d\n", find(u), find(v));
        if(find(u) != find(v)) 
        {
            link(u, i + n); link(v, i + n);
            connect(u, v); return;
        }
        rever(u); access(v); splay(v); int p = pos[v];
        if(e[c(p)].b > e[i].b) 
        {
            cut(e[c(p)].u, p); cut(e[c(p)].v, p);
            link(u, i + n); link(v, i + n);
        }
    }
    int getans()
    {
        rever(1); access(n); splay(n);
        return e[c(pos[n])].b;
    }
} using namespace lct;
int main()
{
//  freopen("magicalforest.in", "r", stdin);
//  freopen("magicalforest.out", "w", stdout);
    scanf("%d%d", &n, &m); Init();
    for(int i = 1; i <= m; ++i) 
    {
        scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].a, &e[i].b);
        if(e[i].u > e[i].v) swap(e[i].u, e[i].v);
    }
    sort(e + 1, e + m + 1, cp);
    for(int i = 1; i <= m; ++i)
    {
        if(e[i].u == e[i].v) continue;
        add(i);
        if(findr(1) == findr(n)) ans = min(ans, e[i].a + getans());
//      printf("%d %d\n", e[i].a, getans());        
    }
    printf("%d\n", ans == 1 << 29 ? -1 : ans);
//  fclose(stdin); fclose(stdout);
    return 0;
}
View Code

 

posted @ 2017-04-20 19:46  19992147  阅读(139)  评论(0编辑  收藏  举报