NOI2014魔法森林题解

题目描述

  • 题目大意
    给定一个无向图,每条边有两个权值 ai bi ,求 1n 路径上 ai 的最大值与 bi 的最大值之和的最小值。
    2n50000
    0m100000
    1ai,bi50,000

题解

  • 膜拜那些会动态开点spfa的神犇们。
    表示本蒟蒻只会用暴力。
    还好是LCT的暴力,bzoj4780ms还不慢。

  • 构造器参数中权值和编号输反了,结果T了半下午。。。。

  • 本题让求两个最小值,直接维护不太方便,所以先按照 ai 排序,再对 bi 用LCT维护动态最小生成树即可。

  • 照例是把边缩成点,标记为 n+1,n+2,,n+i,,n+m ,第n+i个点权值设为第i条边的 bi 。这样,把边按照a递增的值排序后,按kurskal的模式加边。如果加了一条连接u和v的边i,那把LCT中编号为u的点和编号为v的点都和编号为n+i的点连起来,blabla,详见这里。

  • 如果考虑了第i条边以后,1号点已经和n号点连通,那么用 ai+max{bi} 更新答案。因为 ak 是从小到大排序的,所以最大的一定是 ai ,不用再算一遍了;而 bi 要写一个query函数来解决。

Code

#include 
#include 
#include 
#define M 100005
#define N 50005
#define nil T[0]
#define oo 1000000000
using namespace std;
int n, m;
struct node
{
    bool rev;
    int id, val;
    node *fa, *lc, *rc, *mx;
    node(bool rev = false, int id = 0, int val = 0, 
         node *fa = NULL, node *lc = NULL, node *rc = NULL, node *mx = NULL) :
        rev(rev), id(id), val(val), fa(fa), lc(lc), rc(rc), mx(mx) {}
    inline void update()
    {
        mx = this;
        if(mx -> val < lc -> mx -> val) mx = lc -> mx;
        if(mx -> val < rc -> mx -> val) mx = rc -> mx;
    }
    inline void pushdown()
    {
        if(rev)
        {
            lc -> rev ^= 1; rc -> rev ^= 1;
            swap(lc, rc);
            rev = false;
        }
    }
}*T[M + N], *S[M + N];
void zig(node *x)
{
    node *y = x -> fa;
    y -> lc = x -> rc;
    x -> rc -> fa = y;
    x -> rc = y;
    x -> fa = y -> fa;
    if(y == y -> fa -> lc) y -> fa -> lc = x;
    else if(y == y -> fa -> rc) y -> fa -> rc = x;
    y -> fa = x;
    y -> update();
}
void zag(node *x)
{
    node *y = x -> fa;
    y -> rc = x -> lc;
    x -> lc -> fa = y;
    x -> lc = y;
    x -> fa = y -> fa;
    if(y == y -> fa -> lc) y -> fa -> lc = x;
    else if(y == y -> fa -> rc) y -> fa -> rc = x;
    y -> fa = x;
    y -> update();
}
void splay(node *x)
{
    int top = 0;
    S[top++] = x;
    for(node *i = x; i == i -> fa -> lc || i == i -> fa -> rc; i = i -> fa)
    {
        S[top++] = i -> fa;
    }
    while(top--) S[top] -> pushdown();
    node *y = nil, *z = nil;
    while(x == x -> fa -> lc || x == x -> fa -> rc)
    {
        y = x -> fa; z = y -> fa;
        if(x == y -> lc)
        {
            if(y == z -> lc) zig(y);
            zig(x);
        }
        else
        {
            if(y == z -> rc) zag(y);
            zag(x);
        }
    }
    x -> update();
}
inline void access(node *x)
{
    for(node *y = nil; x != nil; y = x, x = x -> fa)
    {
        splay(x);
        x -> rc = y;
        x -> update();
    }
}
inline void makeroot(node *x)
{
    access(x); splay(x); x -> rev ^= 1;
}
inline void lnk(node *x, node *y)
{
    makeroot(x);
    x -> fa = y;
}
inline void cut(node *x, node *y)
{
    makeroot(x);
    access(y); splay(y);
    x -> fa = y -> lc = nil;
    y -> update();
}
inline node *find(node *x)
{
    access(x); splay(x);
    while(x -> lc != nil) x = x -> lc;
    return x;
}
inline node *query(node *x, node *y)
{
    makeroot(x);
    access(y); splay(y);
    return y -> mx;
}
struct edge
{
    int u, v, wa, wb;
    edge(int u = 0, int v = 0, int wa = 0, int wb = 0) :u(u), v(v), wa(wa), wb(wb) {}
    inline bool operator < (const edge &b) const
    {
        return wa < b.wa;
    }
}E[M];
int ufs[N];
inline int find(int x) { return x == ufs[x] ? x : ufs[x] = find(ufs[x]); }
int main()
{
#ifndef ONLINE_JUDGE
    freopen("d.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif
    scanf("%d%d", &n, &m);
    nil = new node();
    *nil = node(false, 0, 0, nil, nil, nil, nil);
    for(int i = 1; i <= n + m; ++i) T[i] = new node(false, i, 0, nil, nil, nil, nil);
    for(int i = 1; i <= n; ++i) ufs[i] = i;
    for(int i = 1; i <= m; ++i)
    {
        scanf("%d%d%d%d", &E[i].u, &E[i].v, &E[i].wa, &E[i].wb);
    }
    sort(E + 1, E + m + 1);
    for(int i = 1; i <= m; ++i)
    {
        T[n + i] -> val = E[i].wb;
        T[n + i] -> mx = T[n + i];
    }
    int ans = oo;
    for(int i = 1; i <= m; ++i)
    {
        int x = find(E[i].u), y = find(E[i].v);
        if(x != y)
        {
            lnk(T[E[i].u], T[n + i]);
            lnk(T[E[i].v], T[n + i]);
            ufs[x] = y;
        }
        else
        {
            node *t = query(T[E[i].u], T[E[i].v]);
            if(t -> val > E[i].wb)
            {
                cut(T[E[t -> id - n].u], t);
                cut(T[E[t -> id - n].v], t);
                lnk(T[E[i].u], T[n + i]);
                lnk(T[E[i].v], T[n + i]);
            }
        }
        if(find(1) == find(n))
        {
            ans = min(ans, E[i].wa + query(T[1], T[n]) -> val);
        }
    }
    if(ans >= oo) puts("-1");
    else printf("%d\n", ans);
    for(int i = 0; i <= n + m; ++i)
    {
        delete T[i];
        T[i] = NULL;
    }
    return 0;
}

你可能感兴趣的:(OI党坚毅的步伐,树结构,动态树LCT)