Loading

12.04 CW 模拟赛 T2.树的链接

算法

全都想到了, 不会读入和 \(\rm{LCA}\)

直接把赛时记录的拉过来

对于 \(50 \%\) 的数据点, 直接输出 \(-1\) 即可

\(20 \%\) 直接预处理即可

注意到一个很强的性质, 即

保证在此之前在城市 \(x\)\(y\) 之间不存在任何路径

也就是说每次连边都是加入割边, 最终的图一定是一个森林

并查集处理, 同连通块之间相当于一颗树, 把最终的树建出来之后, 离线的去处理询问即可, 具体的, 对于最终的树和询问时的树, 只要他们在询问时已经联通, 那么最短路不会发生变化, 即 \(\rm{LCA}\) 不变

时间复杂度 \(\mathcal{O} (q + n \log n + q \log n)\)

至此, 可以解决本题

不是哥们 \(\rm{T2}\)\(\rm{T1}\) 简单多少????

框架

读入的时候边建树边判断 \(-1\) , 建完之后跑 \(\rm{LCA}\) 逐个处理

代码

让我写一写, 第一次写神秘题目
不过把后面的看完再说, 让我看看 \(\rm{T3}\) 怎么个事

#include <bits/stdc++.h>
const int MAXN = 5e5 + 50;

namespace IO {
    inline bool read(int &x) // FALSE 表示没有接下来的了
    {
        int f = 1;
        x = 0;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
            x = x * 10 + ch - '0', ch = getchar();
        return ch == ' ';
    }

}
using namespace IO;

int n, q;

class Sol_Class
{
private:
    struct DSU_Struct
    {
        int fa[MAXN];
        void init() { 
            #pragma GCC unroll 8 
            for (int i = 1; i <= n; ++i) fa[i] = i; 
        }
        int find(int x) { return fa[x] = (x == fa[x] ? fa[x] : find(fa[x])); }
        inline void merge(int u, int v) {
            int fau = find(u), fav = find(v);
            if (fau != fav) fa[fav] = fau;
        }
    } DSU; // 并查集

    struct node
    {
        int to, w;
        int next;
    } Edge[MAXN << 1];
    int Edge_cnt = 0, head[MAXN];
    inline void addedge(int u, int v, int w) {
        Edge[Edge_cnt + 1].next = head[u];
        head[u] = Edge_cnt + 1;
        Edge[Edge_cnt + 1].to = v, Edge[Edge_cnt + 1].w = w;
        Edge_cnt++;
    }

    struct ques
    {
        int type; // 1 表示加边, 0 表示查询
        int x, y, w;
        bool tag; // 表示是否有解
    } Q[MAXN];

    int dep[MAXN]; // 深度
    int listval[MAXN]; // 处理根节点到每个点的距离
    int fa[MAXN][30]; // 倍增的祖宗

    /*离线处理询问*/
    void offline()
    {
        DSU.init();
        #pragma GCC unroll 8
        for (int i = 1; i <= n; ++i) head[i] = -1, listval[i] = 0, dep[i] = -1;
        #pragma GCC unroll 8
        for (int i = 1; i <= q; ++i) {
            int x, y, w; read(x), read(y) ? read(w) : w = -1;
            if (~w) {
                Q[i].type = 1, Q[i].x = x, Q[i].y = y, Q[i].w = w;
                DSU.merge(x, y);
                addedge(x, y, w), addedge(y, x, w);
            } else {
                Q[i].type = 0, Q[i].x = x, Q[i].y = y, Q[i].w = w;
                if (DSU.find(x) != DSU.find(y)) Q[i].tag = false;
                else Q[i].tag = true;
            }
        }
    }

    /*处理 dep , listval, fa*/
    void dfs1(int Now, int fat, int w) {
        dep[Now] = dep[fat] + 1;
        listval[Now] = listval[fat] + w;
        /*处理 fa*/
        fa[Now][0] = fat;
        for (int i = 1; (1 << i) <= dep[Now]; ++i)
            fa[Now][i] = fa[fa[Now][i - 1]][i - 1];

        for (int i = head[Now]; ~i; i = Edge[i].next) {
            int NowTo = Edge[i].to, NowW = Edge[i].w;
            if (NowTo == fat) continue;
            dfs1(NowTo, Now, NowW);
        }
    }

    /*处理倍增信息*/
    void LCA_init()
    {
        #pragma GCC unroll 8
        for (int i = 1; i <= n; ++i) {
            if (~dep[i]) continue;

            dfs1(i, 0, 0);
        }
    }

    /*处理 x, y 的 LCA 点的位置*/
    int LCA(int x, int y)
    {
        if (dep[x] < dep[y]) std::swap(x, y);
        for (int i = 19; i >= 0; i--)
            if (dep[x] - (1 << i) >= dep[y])
                x = fa[x][i];
        
        if (x == y) return x;
        for (int i = 19; i >= 0; i--)
            if (fa[x][i] != fa[y][i])
                x = fa[x][i], y = fa[y][i];

        return fa[x][0];
    }

public:
    void solve()
    {
        scanf("%d %d", &n, &q);

        offline();

        LCA_init();
        #pragma GCC unroll 8
        for (int i = 1; i <= q; ++i) {
            if (Q[i].type == 1) continue;
            if (!Q[i].tag) printf("-1\n");
            else {
                int lca = LCA(Q[i].x, Q[i].y);
                printf("%d\n", -(2 * listval[lca] - listval[Q[i].x] - listval[Q[i].y]));
            }
        }
    }
} Sol;

int main()
{
    Sol.solve();
    return 0;
}

总结

没啥好说的, 简单题, 打不出来真抽象

posted @ 2024-12-04 20:10  Yorg  阅读(10)  评论(0)    收藏  举报