P4180 【模板】严格次小生成树[BJWC2010]

其实这道题大概是一两周之前的考试题, 还是我之前做过的题.
不过考试的时候50分和100分的做法都写跪了, 考试后也没有调出来.

来填坑了.

Bugs

大概知道我考试时代码最大的bug是啥了.
需要维护的是最大边和次大边, 但是我好像维护的是最小边和次小边.
能得分才见鬼了

昨天做的时候制造了很多bug, 捡其中最sb的几个来说一下

  • 上面讲了
  • 倍增维护了向上跳跳到那个位置和路径最大次大值, 我是先跳了之后再求的最大次大值.这样还有70分数据是真的水.
  • 去重里面加了个greater<int>()导致去重失败, 90分, 数据是真的水.

优化

把程序写对了之后, 发现开O2优化能过(而且很快), 不开就超时了, 原因大概是我用了太多的STL里面的东西, 如vector<int>, pair<int, int>, 众所周知, 因为STL使用模板元的缘故, 效率是相当的感动.
于是替换成数组和简陋的手写小结构, 通过.

然后又把合并两个最大值, 次大值的函数替换成运算符+=, +, 并且使用了switch避免了贼慢的分支结构.

然后就卡到了599ms.

真劲呢.

然后就为了优化寻址, 把f(向上跳跳到那个位置)和g(路径最大次大值)合并成一个结构.
反而变慢了一点. 也许是.....的原因吧.

final code

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int N = 100005;
const int M = 300005;
const long long inf_ll = 1e15;
const int MAXIN = 300000;
char IN[MAXIN], *SS = IN, *TT = IN;
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
// #define gc() getchar()

inline int read() {
    int now = 0; register char c = gc();
    for (; !isdigit(c); c = gc());
    for (; isdigit(c); now = now * 10 + c - '0', c = gc());
    return now;
}
using std:: min;
using std:: max;
struct Pair {
    int first, second, third;
    Pair() {}
    Pair(int _, int __) : first(_), second(__) { }
    Pair(int _, int __, int ___) : first(_), second(__), third(___) { }
    Pair operator + (const Pair& o) const {
        switch(first == o.first ? 0 : (first > o.first ? 1 : -1)) {
            case 1:
            return Pair(first, max(o.first, second), o.third); break;
            case -1:
            return Pair(o.first, max(first, o.second), o.third); break;
            default:
            return Pair(first, max(second, o.second), o.third);
        }
    }
    void operator += (const Pair& o) {
        switch(first == o.first ? 0 : (first > o.first ? 1 : -1)) {
            case 1:
            second = max(second, o.first); break;
            case -1:
            second = max(first, o.second); first = o.first; break;
            default:
            second = max(second, o.second);
        }
    }
};
class Graph {
    struct Edge {
        int v, c; Edge* nxt;
        Edge(int _, int __, Edge* ___) : v(_), c(__), nxt(___) {}
    } *head[N];
    int n;
    int dep[N];
    Pair g[N][17];
    void dfs(int u, int fa) {
        dep[u] = dep[fa] + 1;
        for (auto edge = head[u]; edge; edge = edge->nxt) {
            int v = edge->v; if (v == fa) continue;
            g[v][0] = Pair(edge->c, -1, u);
            dfs(v, u);
        }
    }
  public:
    Graph(int _) : n(_) {}
    void AddEdge(int _, int __, int ___) {
        head[_] = new Edge(__, ___, head[_]);
        head[__] = new Edge(_, ___, head[__]);
    }
    void init() {
        g[1][0] = Pair(-1, -1, 0);
        dfs(1, 0);
        for (int i = 1; i < 17; i += 1)
            for (int j = 1; j <= n; j += 1)
                g[j][i] = g[j][i - 1] + g[g[j][i - 1].third][i - 1];
    }
    Pair lca(int u, int v) {
        if (dep[u] < dep[v]) std :: swap(u, v);
        if (v == g[u][0].third) return Pair(-1, -1);
        Pair res = Pair(-1, -1);
        for (int i = 16; ~i; i -= 1)
            if (dep[g[u][i].third] >= dep[v]) {
                res += g[u][i], u = g[u][i].third;
            }
        for (int i = 16; ~i; i -= 1)
            if (g[u][i].third != g[v][i].third)
                res += g[u][i] + g[v][i],
                u = g[u][i].third, v = g[v][i].third;
        return u == v ? res : res + g[u][0] + g[v][0];
    }
};
class Solution {
  private:
    int n, m;
    int find(int u) { return u == f[u] ? u : f[u] = find(f[u]); }
    struct Edge {
        int u, v, c;
        bool operator < (const Edge& o) const {
            return c < o.c;
        }
        Edge() {}
        Edge(int p) : u(read()), v(read()), c(read()) { }
    };
    Graph* G;
    Edge edge[M];
    int f[N], vis[M];
    long long Val;
  public:
    Solution(int _, int __) : n(_), m(__) { }
    void init() {
        G = new Graph(n);
        for (int i = 0; i < m; i += 1)
            edge[i] = Edge(1);
        std:: sort(edge, edge + m);
        for (int i = 1; i <= n; i += 1) f[i] = i;
        int rd = 0; Val = 0;
        for (int i = 0; i < m and rd < n; i += 1) {
            Edge* e = &edge[i];
            int fu = find(e->u), fv = find(e->v);
            if (fu != fv)
                f[fu] = fv, rd += 1, Val += 1ll * e->c,
                G->AddEdge(e->u, e->v, e->c), vis[i] = true;
            else vis[i] = false;
        }
        G->init();
    }
    long long getans() {
        long long Res = inf_ll;
        for (int i = 0; i < m; i += 1)
            if (not vis[i]) {
                auto e = &edge[i];
                int u = e->u, v = e->v, c = e->c;
                Pair p = G->lca(u, v);
                if (p.first == c) {
                    if (~p.second) Res = std:: min(Res, Val + c - p.second);
                } else Res = std:: min(Res, Val + c - p.first);
            }
        return Res;
    }
};

int main () {
    int n = read(), m = read();
    Solution* Sol = new Solution(n, m);
    Sol->init();
    std:: cout << Sol->getans();
    return 0;
}
posted @ 2018-10-23 09:02  Grary  阅读(105)  评论(0编辑  收藏  举报
博客园 首页 私信博主 编辑 关注 管理 新世界