[NOI2014] Enchanted Forest - Link Cut Tree

[NOI2014] Enchanted Forest

Description

Given a map, each edge \ (I \) right to \ ((a_i, B_i) \) , seeking a \ (1 \ sim n \) path, to minimize \ (\ max_ {i \ in P } {a_i} + \ max_ { i \ in P} {b_i} \)

Solution

If we define the maximum of \ (b_i \) , then the path must be in order to \ (a_i \) on the minimum spanning tree to the right.

Proof. Consider evidence to the contrary, assume that the path has an edge not the MST, then this non-tree edges must form a ring with the tree, it is clear that with this edge to replace any one of the other side of the ring on the spanning tree may be reduced weights and conditions of the minimum spanning tree of the contradiction.

With this configuration the nature of the algorithm. Our small to large enumeration \ (b_i \) maximum, in turn, added with the tree, and with LCT maintained to \ (a_i \) minimum spanning tree to the right to edge.

Method of maintaining the minimum spanning tree is very simple. LCT maintain maximum utilization chain tree, when a new edge \ ((u, v, w ) \) is added, if we consider this edge than the tree chain \ (u \ sim v \) small maximum value, then it replace it with the edge of the maximum value. Hence the need to maintain the position of the maximum value and the maximum value of the LCT.

Use the right side of the LCT maintenance is common practice to build point-to-edge, the right to assign points to the right side, but the real point is not the right to have a point. While maintaining the basic information edge.

Set forth below is a more specific implementations

In this problem, we can use the number \ (1 \ sim n \) points to represent the real point, by number (n + 1 \ sim n + m \) \ dots to represent the edge, while an array of structures in in ((u, v, w) \) \ record basic information in the form of the right side. No side note can be used in accordance with the \ (b_i \) is replaced by the keyword ranking.

On the implementation level of the LCT, we can tentatively ignore it all, the whole point number as the maximum point right point and the right to maintain maximum tree chain.

When we need to query \ (u \ sim v \) maximum right of the edge between, we only need to ask in the LCT.

When we need to remove one side, we only need to know the number \ (i \) , and then disconnect \ ((u_i, n + i ) \) and \ ((v_i, n + i ) \)

When we need to add an edge, we only need to know the number \ (i \) , and then connect \ ((u_i, n + i ) \) and \ ((v_i, n + i ) \)

Code
#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1000000;

int n,m;

struct Edge {
    int u,v,w,b;
    bool operator < (const Edge &x) const {
        return b < x.b;
    }
} e[N];

struct LinkCutTree {
    int top, q[N], ch[N][2], fa[N], rev[N], mx[N], mp[N], val[N];
    inline void pushup(int x) {
        mx[0]=mp[0]=0;
        mx[x] = max(max(mx[ch[x][0]],mx[ch[x][1]]),val[x]);
        if(mx[x] == mx[ch[x][0]])
            mp[x]=mp[ch[x][0]];
        if(mx[x] == mx[ch[x][1]])
            mp[x]=mp[ch[x][1]];
        if(mx[x] == val[x])
            mp[x]=x;
    }
    inline void pushdown(int x) {
        if(!rev[x])
            return;
        rev[ch[x][0]]^=1;
        rev[ch[x][1]]^=1;
        rev[x]^=1;
        swap(ch[x][0],ch[x][1]);
    }
    inline bool isroot(int x) {
        return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
    }
    inline void rotate(int p) {
        int q=fa[p], y=fa[q], x=ch[fa[p]][1]==p;
        ch[q][x]=ch[p][x^1];
        fa[ch[q][x]]=q;
        ch[p][x^1]=q;
        fa[q]=p;
        fa[p]=y;
        if(y)
            if(ch[y][0]==q)
                ch[y][0]=p;
            else  if(ch[y][1]==q)
                ch[y][1]=p;
        pushup(q);
        pushup(p);
    }
    inline void splay(int x) {
        q[top=1]=x;
        for(int i=x; !isroot(i); i=fa[i])
            q[++top]=fa[i];
        for(int i=top; i; i--)
            pushdown(q[i]);
        for(; !isroot(x); rotate(x))
            if(!isroot(fa[x]))
                rotate((ch[fa[x]][0]==x)==(ch[fa[fa[x]]][0]==fa[x])?fa[x]:x);
    }
    void access(int x) {
        for(int t=0; x; t=x,x=fa[x])
            splay(x),ch[x][1]=t,pushup(x);
    }
    void makeroot(int x) {
        access(x);
        splay(x);
        rev[x]^=1;
    }
    int find(int x) {
        access(x);
        splay(x);
        while(ch[x][0])
            x=ch[x][0];
        return x;
    }
    void split(int x,int y) {
        makeroot(x);
        access(y);
        splay(y);
    }
    void cut(int x,int y) {
        split(x,y);
        if(ch[y][0]==x)
            ch[y][0]=0, fa[x]=0;
    }
    void link(int x,int y) {
        makeroot(x);
        fa[x]=y;
    }
    void setval(int p,int v) {
        val[p]=mx[p]=v;
        mp[p]=p;
    }
    int queryv(int p,int q) {
        split(p,q);
        return mx[q];
    }
    int queryp(int p,int q) {
        split(p,q);
        return mp[q];
    }
} lct;

bool check(int p,int q) {
    return lct.find(p)==lct.find(q);
}

int queryv(int p,int q) {
    return lct.queryv(p,q);
}

int queryp(int p,int q) {
    return lct.queryp(p,q)-n;
}

void link(int i) {
    lct.link(n+i,e[i].u);
    lct.link(n+i,e[i].v);
}

void cut(int i) {
    lct.cut(n+i,e[i].u);
    lct.cut(n+i,e[i].v);
}

int ans = 1e+12;

signed main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].w,&e[i].b);
    }
    sort(e+1,e+m+1);
    for(int i=1;i<=n;i++) lct.setval(i, 0);
    for(int i=1;i<=m;i++) lct.setval(i+n, e[i].w);
    for(int i=1;i<=m;i++) {
        if(check(e[i].u,e[i].v)) {
            int v=queryv(e[i].u,e[i].v), p=queryp(e[i].u,e[i].v);
            if(v > e[i].w) {
                cut(p);
                link(i);
            }
        }
        else {
            link(i);
        }
        if(check(1,n)) {
            ans = min(ans, queryv(1,n) + e[i].b);
        }

    }
    if(ans < (int)1e+12) cout<<ans<<endl;
    else cout<<-1<<endl;
}

Guess you like

Origin www.cnblogs.com/mollnn/p/11701272.html