《P4180 [BJWC2010]严格次小生成树》

好久没码题了,码力好像有点下降。

这题有结论可知:枚举没条不在最小生成树上的边,将这条边连上成环,那么就可以去掉环上的最长边(除了新加的这条)。

因为这里是严格次小树,那么最长边就不能和这条新边相等,显然这条最长边只能 <= 新边,如果大于的话,那么最小生成树就可以有更小的。

倍增维护最小值和次小值,如果光维护最小值,那么可能最长边 == 新边,维护次小值就能避免这点。

u 写成了 i调试了n久。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 3e5 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

int n,m,fa[N],f[N][20],dep[N],lg[N],tag[N];//ff - father
LL Mx[N][20],Sx[N][20];
struct Edge{
    int st,to,dis;
    bool operator < (const Edge a)const{
        return dis < a.dis;
    }
}e[M];
vector<Edge> G[N];
void init(){
    for(int i = 1;i < N;++i) lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
}
int Find(int x){
    return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
void dfs(int u,int ffa,int len){
    dep[u] = dep[ffa] + 1;
    f[u][0] = ffa,Mx[u][0] = len,Sx[u][0] = -INF;
    for(int i = 1;i <= lg[dep[u]];++i) {
        f[u][i] = f[f[u][i - 1]][i - 1];
        Mx[u][i] = max(Mx[u][i - 1],Mx[f[u][i - 1]][i - 1]);
        Sx[u][i] = max(Sx[u][i - 1],Sx[f[u][i - 1]][i - 1]);
        if(Mx[u][i - 1] > Mx[f[u][i - 1]][i - 1]) Sx[u][i] = max(Sx[u][i],Mx[f[u][i - 1]][i - 1]);
        else if(Mx[u][i - 1] < Mx[f[u][i - 1]][i - 1]) Sx[u][i] = max(Sx[u][i],Mx[u][i - 1]); 
    }
    for(auto v : G[u]) if(v.to != ffa) dfs(v.to,u,v.dis);
}
LL solve(int x,int y,int up){
    if(dep[x] < dep[y]) swap(x,y);
    LL ans = -1;
    while(dep[x] > dep[y]){
        int step = lg[dep[x] - dep[y]] - 1;
        if(Mx[x][step] != up) ans = max(ans,Mx[x][step]);
        else ans = max(ans,Sx[x][step]);
        x = f[x][step];
    }
    if(x == y) return ans;
    for(int i = lg[dep[x]] - 1;i >= 0;--i){
        if(f[x][i] != f[y][i]){
            if(Mx[x][i] != up) ans = max(ans,Mx[x][i]);
            else ans = max(ans,Sx[x][i]);
            if(Mx[y][i] != up) ans = max(ans,Mx[y][i]);
            else ans = max(ans,Sx[y][i]);
            x = f[x][i],y = f[y][i];
        }
    }
    if(x == y) return ans;
    if(Mx[x][0] != up) ans = max(Mx[x][0],ans);
    if(Mx[y][0] != up) ans = max(Mx[y][0],ans);
    return ans;
}
int main()
{
    init();
    n = read(),m = read();
    for(int i = 1;i <= n;++i) fa[i] = i;
    LL sum = 0;
    for(int i = 1;i <= m;++i){
        e[i].st = read(),e[i].to = read(),e[i].dis = read();
    }
    sort(e + 1,e + m + 1);
    for(int i = 1;i <= m;++i){
        int xx = Find(e[i].st),yy = Find(e[i].to);
        if(xx != yy){
            fa[xx] = yy;
            G[e[i].st].push_back(Edge{e[i].st,e[i].to,e[i].dis});
            G[e[i].to].push_back(Edge{e[i].to,e[i].st,e[i].dis});
            tag[i] = 1;
            sum += e[i].dis;
        }
    }
    dfs(1,0,0);
    LL ans = INF;
    for(int i = 1;i <= m;++i){
        if(tag[i] == 1) continue;
        LL temp = solve(e[i].st,e[i].to,e[i].dis);
        //printf("x is %d y is %d tmp is %lld\n",e[i].st,e[i].to,temp);
        ans = min(ans,sum - temp + e[i].dis);
    }
    printf("%lld\n",ans);
    system("pause");
    return 0;
}
View Code

 

posted @ 2021-01-14 16:20  levill  阅读(97)  评论(0编辑  收藏  举报