【BZOJ4736】【UOJ274】温暖会指引我们前行(LCT)

本文介绍了一道BZOJ极其优美的题目——[BZOJ4736][UOJ274]温暖会指引我们前行的解题思路。主要使用LCT(Link-Cut Tree)维护最大生成树解决三种操作:加边、询问和更改距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

来来来,看看BZOJ极其优美的题面 (滑稽(^o^)/~)


Solution

LCT维护最大生成树的裸题。
三种操作:
1. 加边
- 如果本来两点之间不联通,那么直接连上
- 如果联通,那么判断两点之间的最小值小于新边的边权,那么删去最小的边,加上新边,否则不进行操作。
2. 询问
没什么好说的
3. 更改距离
距离不影响我们的树,直接修改即可。

这题打得挺快的,BZOJ上也AC了,然后UOJ上莫名TLE了Extra Test 5
TM是谁搞了Extra Test这个鬼东西的
于是把之前偷懒写的__gnu_pbds::cc_hash_table改掉,然后将判是否联通改成并查集就过去了。。。


Source

/************************************************
 * Au: Hany01
 * Date: Apr 3rd, 2018
 * Prob: [BZOJ4736][UOJ274] 温暖会指引我们前行
 * Email: hany01@foxmail.com
************************************************/

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia

template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read()
{
    register int _, __; register char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

const int maxn = 100005, maxm = 300005;

int n, len[maxn + maxm], temp[maxn + maxm], eu[maxm], ev[maxm], fa[maxn];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

struct LCT
{
    int fa[maxn + maxm], ch[maxn + maxm][2], mt[maxn + maxm], sl[maxn + maxm], rev[maxn + maxm], id[maxn + maxm];

#define dir(x) (ch[fa[x]][1] == x)
#define isrt(x) (ch[fa[x]][1] != x && ch[fa[x]][0] != x)

    inline void pushdown(int u) {
        if (rev[u]) rev[u] = 0, rev[ch[u][0]] ^= 1, rev[ch[u][1]] ^= 1, swap(ch[u][0], ch[u][1]);
    }

    inline void maintain(int u)
    {
        mt[u] = min(mt[ch[u][0]], min(mt[ch[u][1]], temp[u]));
        if (mt[u] == temp[u]) id[u] = u;
        else if (mt[u] == mt[ch[u][0]]) id[u] = id[ch[u][0]];
        else id[u] = id[ch[u][1]];
        sl[u] = sl[ch[u][0]] + sl[ch[u][1]] + len[u];
    }

    inline void rotate(int u)
    {
        int f = fa[u], gf = fa[f], d = dir(u);
        fa[ch[f][d] = ch[u][d ^ 1]] = f;
        fa[u] = gf;
        if (!isrt(f)) ch[gf][dir(f)] = u;
        ch[u][d ^ 1] = f, fa[f] = u;
        maintain(f), maintain(u);
    }

    int stk[maxn + maxm], top;
    inline void splay(int u)
    {
        stk[top = 1] = u;
        for (int t = u; !isrt(t); t = fa[t]) stk[++ top] = fa[t];
        while (top) pushdown(stk[top --]);
        for ( ; !isrt(u); rotate(u)) if (!isrt(fa[u]))
            rotate(dir(u) == dir(fa[u]) ? fa[u] : u);
    }

    inline void access(int u)
    {
        for (register int t = 0; u; t = u, u = fa[u])
            splay(u), ch[u][1] = t, maintain(u);
    }

    inline void makeroot(int u) {
        access(u), splay(u), rev[u] ^= 1;
    }

    inline void split(int u, int v) { makeroot(u), access(v), splay(v); }

    inline int findroot(int u) {
        access(u), splay(u);
        while (ch[u][0]) u = ch[u][0];
        return u;
    }

    inline void link(int u, int v) {
        //assert(findroot(u) == findroot(v));
        makeroot(u), fa[u] = v;
    }

    inline void cut(int u, int v) { split(u, v), fa[u] = ch[v][0] = 0; }

}lct;

int main()
{
#ifdef hany01
    File("bzoj4736");
#endif

    static char type[10];

    n = read();
    Set(lct.mt, 127), Set(temp, 127);
    For(i, 1, n) fa[i] = i;
    for (static int m = read(); m --; )
    {
        register int id, u, v;
        scanf("%s", type);
        if (type[0] == 'f') {
            id = read() + 1, u = read() + 1, v = read() + 1, temp[n + id] = read(), len[n + id] = read();
            if (u > v) swap(u, v);
            eu[id] = u, ev[id] = v;
            if (find(u) == find(v))
            {
                lct.split(u, v);
                if (lct.mt[v] < temp[n + id]) {
                    register int tmp = lct.id[v] - n;
                    lct.cut(eu[tmp], tmp + n), lct.cut(ev[tmp], tmp + n);
                    lct.link(u, n + id), lct.link(v, n + id);
                }
            } else lct.link(u, n + id), lct.link(n + id, v), fa[find(u)] = find(v);
        }
        else if (type[0] == 'm') {
            u = read() + 1, v = read() + 1;
            if (find(u) != find(v)) puts("-1");
            else {
                lct.split(u, v);
                if (lct.findroot(v) != u) puts("-1");
                else printf("%d\n", lct.sl[v]);
            }
        } else
            id = read() + 1 + n, lct.splay(id), len[id] = read(), lct.maintain(id);
    }

    return 0;
}
//戚姬髡发入舂市,万古共悲辛。
//    -- 李白《中山孺子妾歌》
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值