[BZOJ1977][Beijing2010组队][LCA][Kruskal]次小生成树

来源:互联网 发布:阿里云服务器管理 编辑:程序博客网 时间:2024/06/05 10:16
[Problem Description]
小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)  这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
[Algorithm]
LCA ST 最小生成树Kruskal
[Analysis]
首先求出最小生成树。可以想到严格次小生成树就是将一条边与最小生成树中的一条边进行替换,要求必须要替换代价且替换代价最小。枚举每条没有在最小生成树中的边,求出这条边连接的两个点在最小生成树中路径上的最大的边(这样替换代价最小)。由于这条边和两点间最小生成树上的路径构成了一个环,所以从环上任意去掉一个边,点都是联通的。至于求两点树上路径最大边,用lca的st算法。还要注意的是,由于是严格次小生成树,所以还要维护两点间树上路径上次大的边,当两点间树上路径最大边与枚举的边相等的时候,将次大的边与枚举的边替换。
[Pay Attention]
LCA算法注意别忘了将x和y更新!!我因为这个问题调了半天……以后要注意使用静态查错了……
[Code]
/**************************************************************    Problem: 1977    User: gaotianyu1350    Language: C++    Result: Accepted    Time:2920 ms    Memory:35596 kb****************************************************************/ #include <cstdio>#include <cmath>#include <cstring>#include <cstdlib>#include <queue>#include <algorithm>#include <iostream>using namespace std; const int MAXN = 100100;const int MAXM = 300100;const int MAXBIT = 22;const long long INF = 1e15; struct edge{    int x, y, z;    bool operator < (const edge b) const    {        return z < b.z;    }} e[MAXM]; int point[MAXN] = {0}, next[MAXM] = {0}, v[MAXM], w[MAXM];int tot = 0; bool check[MAXM] = {0};int deep[MAXN] = {0}, f[MAXN][MAXBIT] = {0}, maxedge[MAXN][MAXBIT] = {0}, lessedge[MAXN][MAXBIT] = {0};int n, m;long long ans = INF;long long minCost = 0;int theMaxBit; int father[MAXN]; inline void UnionInit(){    for (int i = 1; i <= n; i++)        father[i] = i;} inline void addedge(int x, int y, int z){    tot++;    next[tot] = point[x];    point[x] = tot;    v[tot] = y;    w[tot] = z;} int getfather(int x){    if (father[x] == x) return x;    else return father[x] = getfather(father[x]);} inline void update(int &theMax, int &theLess, int x1, int y1, int x2, int y2){    if (x1 > x2)    {        theMax = x1;        theLess = max(y1, x2);    }    else if (x1 < x2)    {        theMax = x2;        theLess = max(x1, y2);    }    else    {        theMax = x1;        theLess = max(y1, y2);    }} inline void MakeLca(){    queue<int> q;    q.push(1);    deep[1] = 1;    while (!q.empty())    {        int now = q.front();        q.pop();        for (int temp = point[now]; temp; temp = next[temp])            if (v[temp] != f[now][0])            {                q.push(v[temp]);                f[v[temp]][0] = now;                maxedge[v[temp]][0] = w[temp];                lessedge[v[temp]][0] = 0;                deep[v[temp]] = deep[now] + 1;            }    }    //theMaxBit = MAXBIT;    theMaxBit = (int)(log(n) / log(2) + 1);    for (int Bit = 1; Bit <= theMaxBit; Bit++)        for (int i = 1; i <= n; i++)        {            f[i][Bit] = f[f[i][Bit - 1]][Bit - 1];            update(maxedge[i][Bit], lessedge[i][Bit],                    maxedge[i][Bit - 1], lessedge[i][Bit - 1],                   maxedge[f[i][Bit - 1]][Bit - 1], lessedge[f[i][Bit - 1]][Bit - 1]);        }} inline void Up(int &x, int tar, int &theMax, int &theLess){    for (int i = theMaxBit; i >= 0; i--)        if (deep[f[x][i]] >= tar)        {            update(theMax, theLess, theMax, theLess, maxedge[x][i], lessedge[x][i]);            x = f[x][i];        }} void Query(int x, int y, int &theMax, int &theLess){    theMax = -1;    theLess = -1;    if (deep[x] < deep[y])    {        int temp = x;        x = y;        y = temp;    }    Up(x, deep[y], theMax, theLess);    if (x == y) return;    for (int i = theMaxBit; i >= 0; i--)        if (f[x][i] != f[y][i])        {            update(theMax, theLess, theMax, theLess,                   maxedge[x][i], lessedge[x][i]);            update(theMax, theLess, theMax, theLess,                   maxedge[y][i], lessedge[y][i]);            x = f[x][i]; y = f[y][i];        }    update(theMax, theLess, theMax, theLess,           maxedge[x][0], lessedge[x][0]);    update(theMax, theLess, theMax, theLess,           maxedge[y][0], lessedge[y][0]);} int main(){    //freopen("input.txt", "r", stdin);    scanf("%d%d", &n, &m);    UnionInit();    for (int i = 1; i <= m; i++)        scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].z);    sort(e + 1, e + 1 + m);    for (int i = 1; i <= m; i++)    {        int fx = getfather(e[i].x);        int fy = getfather(e[i].y);        if (fx != fy)        {            check[i] = true;            father[fx] = fy;            addedge(e[i].x, e[i].y, e[i].z);            addedge(e[i].y, e[i].x, e[i].z);            minCost += e[i].z;        }    }    MakeLca();    for (int i = 1; i <= m; i++)        if (!check[i])        {            int theMax, theLess;            Query(e[i].x, e[i].y, theMax, theLess);            if (theMax != e[i].z)            {                long long temp = minCost - theMax;                temp += e[i].z;                ans = temp < ans ? temp : ans;            }            else if (theLess > 0)            {                long long temp = minCost - theLess;                temp += e[i].z;                ans = temp < ans ? temp : ans;            }        }    printf("%lld\n", ans);}


0 0
原创粉丝点击