[Noi2014]魔法森林 LCT+并查集+最小生成树

Description
有N个点,有M条边,每条边有权值为ai,bi。
现在让你求1~n任意一条路径使max(ai)+max(bi)值最小。


Sample Input
4 5
1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17


Sample Output
32


你考虑第一维就最小生成树做,然后第二问。
这道题由于它是边权,于是你要考虑重构树的思想,把边转化成一个点。
你新加入这条边构成了环的话,那你考虑删除最大的那条边。
删除其实直接把这个便所代表的点和它连接的两个点Cut就好了。


#include 
#include 
#include 

using namespace std;
int _min(int x, int y) {return x < y ? x : y;}

struct node {
    int x, y, a, b;
} a[210000];
struct trnode {
    int md, f, lazy, son[2]; 
} t[210000];
int n, tp, temp[210000], s[210000], fa[51000];

bool cmp(node a, node b) {return a.a < b.a;}

int findfa(int x) {
    if(fa[x] != x) fa[x] = findfa(fa[x]);
    return fa[x];
}

void update(int x) {
    int lc = t[x].son[0], rc = t[x].son[1];
    t[x].md = x;
    if(s[t[lc].md] > s[t[x].md]) t[x].md = t[lc].md;
    if(s[t[rc].md] > s[t[x].md]) t[x].md = t[rc].md;
}

void rotate(int x, int fx) {
    int f = t[x].f, ff = t[f].f;
    int r, R;

    r = t[x].son[fx], R = f;
    t[R].son[1 ^ fx] = r;
    if(r) t[r].f = R;

    r = x, R = ff;
    if(t[ff].son[0] == f) t[R].son[0] = r; else if(t[ff].son[1] == f) t[R].son[1] = r;
    t[r].f = R;

    r = f, R = x;
    t[R].son[fx] = r;
    t[r].f = R;

    update(f); update(x);
}

void Lazy(int x) {
    if(!t[x].lazy) return ;
    t[x].lazy = 0;
    swap(t[x].son[0], t[x].son[1]);
    int lc = t[x].son[0], rc = t[x].son[1];
    if(lc) t[lc].lazy ^= 1;
    if(rc) t[rc].lazy ^= 1;
}

bool hh(int x) {
    int f = t[x].f;
    if(f == 0 || (t[f].son[0] != x && t[f].son[1] != x)) return 0;
    return 1;
}

void splay(int x) {
    int i = x; tp = 0;
    while(hh(i)) temp[++tp] = i, i = t[i].f;
    temp[++tp] = i;
    for(int i = tp; i >= 1; i--) Lazy(temp[i]);
    while(hh(x)) {
        int f = t[x].f, ff = t[f].f;
        if(!hh(f)) {
            if(t[f].son[0] == x) rotate(x, 1);
            else rotate(x, 0);
        }
        else if(t[ff].son[0] == f && t[f].son[0] == x) rotate(f, 1), rotate(x, 1);
        else if(t[ff].son[0] == f && t[f].son[1] == x) rotate(x, 0), rotate(x, 1);
        else if(t[ff].son[1] == f && t[f].son[1] == x) rotate(f, 0), rotate(x, 0);
        else if(t[ff].son[1] == f && t[f].son[0] == x) rotate(x, 1), rotate(x, 0);
    }
}

void Access(int x) {
    int y = 0;
    while(x) {
        splay(x);
        t[x].son[1] = y;
        if(y) t[y].f = x;
        update(x);
        y = x; x = t[x].f;
    }
}

void Makert(int x) {
    Access(x); splay(x);
    t[x].lazy ^= 1;
}

void Link(int x, int y) {
    Makert(x);
    t[x].f = y;
    Access(x);
}

void Cut(int x, int y) {
    Makert(x);
    Access(y); splay(y);
    t[t[y].son[0]].f = 0; t[y].son[0] = 0;
    update(y);
}

int solve(int x, int y) {
    Makert(x);
    Access(y); splay(y);
    return t[y].md;
}

int main() {
    int n, m; scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) fa[i] = i;
    for(int i = 1; i <= m; i++) scanf("%d%d%d%d", &a[i].x, &a[i].y, &a[i].a, &a[i].b);
    sort(a + 1, a + m + 1, cmp);
    int ans = 999999999;
    for(int i = 1; i <= m; i++) {
        s[i + n] = a[i].b;
        int fx = findfa(a[i].x), fy = findfa(a[i].y);
        int x = a[i].x, y = a[i].y;
        if(fx == fy) {
            int dd = solve(x, y);
            if(s[dd] <= a[i].b) continue;
            Cut(a[dd - n].x, dd);
            Cut(dd, a[dd - n].y);
        }
        else fa[fx] = fy;
        Link(x, i + n); Link(i + n, y);
        if(findfa(1) == findfa(n)) ans = _min(ans, a[i].a + s[solve(1, n)]);
    }
    if(ans == 999999999) printf("-1\n");
    else printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(LCT,最小生成树,xgc的做题记录)