zoukankan      html  css  js  c++  java
  • 魔法森林

    LCT
    a排序后做b的kruskal
    splay维护最大边的位置,若当前大,不加,否则cut,加边

    # include <stdio.h>
    # include <stdlib.h>
    # include <iostream>
    # include <algorithm>
    # include <string.h>
    # define IL inline
    # define RG register
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    
    IL ll Read(){
        RG char c = getchar(); RG ll x = 0, z = 1;
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0';
        return x * z;
    }
    
    const int MAXN(2e5 + 10);
    int S[MAXN], n, m, ans = 1 << 30;
    struct Edge{
        int u, v, a, b;
        IL bool operator <(RG Edge B) const{  return a < B.a;  }
    } edge[MAXN];
    struct Tree{  int fa, ch[2], rev, maxb;  } t[MAXN];
    
    IL bool Isroot(RG int x){  return t[t[x].fa].ch[0] != x && t[t[x].fa].ch[1] != x;  }
    
    IL void Update(RG int x){
        t[x].maxb = x;
        if(edge[t[t[x].ch[0]].maxb].b > edge[t[x].maxb].b) t[x].maxb = t[t[x].ch[0]].maxb;
        if(edge[t[t[x].ch[1]].maxb].b > edge[t[x].maxb].b) t[x].maxb = t[t[x].ch[1]].maxb;
    }
    
    IL void Pushdown(RG int x){
        if(!t[x].rev) return;
        swap(t[x].ch[0], t[x].ch[1]);
        t[x].rev = 0; t[t[x].ch[0]].rev ^= 1; t[t[x].ch[1]].rev ^= 1;
    }
    
    IL bool Son(RG int x){  return t[t[x].fa].ch[1] == x;  }
    
    IL void Rot(RG int x){
        RG int y = t[x].fa, z = t[y].fa, c = Son(x);
        if(!Isroot(y)) t[z].ch[Son(y)] = x; t[x].fa = z;
        t[y].ch[c] = t[x].ch[!c]; t[t[y].ch[c]].fa = y;
        t[x].ch[!c] = y; t[y].fa = x;
        Update(y);
    }
    
    IL void Splay(RG int x){
        RG int top = 0; S[++top] = x;
        for(RG int y = x; !Isroot(y); y = t[y].fa) S[++top] = t[y].fa;
        while(top) Pushdown(S[top--]);
        for(RG int y = t[x].fa; !Isroot(x); Rot(x), y = t[x].fa)
            if(!Isroot(y)) Son(x) ^ Son(y) ? Rot(x) : Rot(y);
        Update(x);
    }
    
    IL void Access(RG int x){  for(RG int y = 0; x; y = x, x = t[x].fa) Splay(x), t[x].ch[1] = y, Update(x);  }
    
    IL void Makeroot(RG int x){  Access(x); Splay(x); t[x].rev ^= 1;  }
    
    IL int Findroot(RG int x){  Access(x); Splay(x); while(t[x].ch[0]) x = t[x].ch[0]; return x;  }
    
    IL void Split(RG int x, RG int y){  Makeroot(x); Access(y); Splay(y);   }
    
    IL void Link(RG int x, RG int y){  Makeroot(x); t[x].fa = y;  }
    
    IL void Cut(RG int x, RG int y){  Split(x, y); t[x].fa = t[y].ch[0] = 0;  }
    
    IL int Query(RG int u, RG int v){  Split(u, v); return t[v].maxb;  }
    
    int main(RG int argc, RG char* argv[]){
        n = Read(); m = Read();
        for(RG int i = 1; i <= m; i++) edge[i] = (Edge){Read(), Read(), Read(), Read()};
        sort(edge + 1, edge + m + 1);
        for(RG int i = 1; i <= m; i++){
            RG int u = edge[i].u + m, v = edge[i].v + m;
            if(Findroot(u) != Findroot(v)) Link(u, i), Link(v, i);
            else{
                RG int mx = Query(u, v);
                if(edge[i].b < edge[mx].b) Cut(edge[mx].u + m, mx), Cut(edge[mx].v + m, mx), Link(u, i), Link(v, i);
            }
            if(Findroot(1 + m) == Findroot(n + m)) ans = min(ans, edge[i].a + edge[Query(1 + m, n + m)].b);
        }
        printf("%d
    ", ans != (1 << 30) ? ans : -1);
        return 0;
    }
  • 相关阅读:
    MYSQL判断某个表是否已经存在
    百度、雅虎、谷歌搜索引擎接口调用注意事项
    Codeigniter整合Tank Auth权限类库的教程
    短链接的生成算法
    自定义String
    运算符和结合性
    字符串类封装
    运算符重载
    数组类封装
    友元
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8206377.html
Copyright © 2011-2022 走看看