• 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
    ", 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
    ", e[i].a, getans());        
        }
        printf("%d
    ", ans == 1 << 29 ? -1 : ans);
    //  fclose(stdin); fclose(stdout);
        return 0;
    }
    View Code
  • 相关阅读:
    原创 动态卷积
    BZOJ1565 植物大战僵尸
    BZOJ1143 [CTSC2008] 祭祀river
    BZOJ3438 小M的作物
    BZOJ3144 [HNOI2013]切糕
    BZOJ2039 [2009国家集训队]employ人员雇佣
    BZOJ1066[SCOI2007]蜥蜴
    BZOJ3874 codevs3361 宅男计划
    Codeforces Round #343 (Div. 2)
    [转]后缀自动机(SAM)
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6740495.html
Copyright © 2020-2023  润新知