bzoj 1977 [BeiJing2010组队]次小生成树 Tree [严格的次小生成树]

来源:互联网 发布:网络摄像机客户端 编辑:程序博客网 时间:2024/05/17 10:39

1977: [BeiJing2010组队]次小生成树 Tree

Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 2777 Solved: 695

Description

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input

5 6

1 2 1

1 3 2

2 4 3

3 5 4

3 4 3

4 5 6

Sample Output
11

HINT

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。


这道题要求严格的次小MST,思路差不多,但是不能只记录max,还要记录次大值max2,更新的时候分情况讨论,具体看代码。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<string>#include<iomanip>#include<ctime>#include<climits>#include<cctype>#include<algorithm>#ifdef WIN32#define AUTO "%I64d"#else#define AUTO "%lld"#endifusing namespace std;#define smax(x,tmp) x=max((x),(tmp))#define smin(x,tmp) x=min((x),(tmp))#define maxx(x1,x2,x3) max(max(x1,x2),x3)#define minn(x1,x2,x3) min(min(x1,x2),x3)typedef long long LL;const LL INF=(1ll<<60);const int maxn = 100005;const int maxm = 300005;struct Edge{    int to,next;    int val;}edge[maxn<<1]; // set for the MSTint head[maxn];int maxedge;inline void addedge(int u,int v,int c){    edge[++maxedge] = (Edge) { v,head[u],c };    head[u] = maxedge;    edge[++maxedge] = (Edge) { u,head[v],c };    head[v] = maxedge;}struct Road{    int u,v;    int c;    bool operator < (const Road t) const    {        return c < t.c;    }}road[maxm];bool used[maxm];int n,m;LL MST;int fa[maxn];int find(int x) { return fa[x]^x? fa[x]=find(fa[x]) : x ; }inline bool union_find(int x,int y){    int t1=find(x),t2=find(y);    if(t1==t2) return false;    fa[t2]=t1;    return true;}LL kruskal(){    int tot = 0;    LL ans = 0ll;    for(int i=1;i<=m;i++)    {        if(union_find(road[i].u,road[i].v)) tot++,ans+=road[i].c,addedge(road[i].u,road[i].v,road[i].c),used[i]=true;        if(tot==n-1) break;    }    return ans;}#define maxd 25#define D 20int f[maxn][maxd];int dp[maxn][maxd][2];int depth[maxn];void dfs(int u,int father,int dep){    depth[u] = dep;    for(int k=1;k<=D;k++)    {        f[u][k] = f[f[u][k-1]][k-1];        dp[u][k][0] = max(dp[u][k-1][0],dp[f[u][k-1]][k-1][0]);        if(dp[u][k-1][0] == dp[f[u][k-1]][k-1][0]) dp[u][k][1] = max(dp[u][k-1][1],dp[f[u][k-1]][k-1][1]);        else        {            dp[u][k][1] = min(dp[u][k-1][0],dp[f[u][k-1]][k-1][0]);            smax(dp[u][k][1] , max(dp[u][k-1][1],dp[f[u][k-1]][k-1][1]));        }    }    for(int i=head[u];~i;i=edge[i].next)    {        int v = edge[i].to;        if(v==father) continue;        f[v][0] = u;        dp[v][0][0] = (LL)edge[i].val;        // provided two number differs!        dfs(v,u,dep+1);    }}inline void merge(int &ans1,int &ans2,int u,int k){    int t1 = max(ans1,dp[u][k][0]) , t2;    if(ans1 == dp[u][k][0]) t2 = max(ans2,dp[u][k][1]);    else    {        t2 = min(ans1,dp[u][k][0]);        smax(t2,max(ans2,dp[u][k][1]));    }    ans1 = t1;    ans2 = t2;}pair <int,int> query(int u,int v){    int ans1 = 0;    int ans2 = 0;    if(depth[u]<depth[v]) swap(u,v);    for(int k=D;k>=0;k--) if(depth[f[u][k]]>=depth[v])    {        merge(ans1,ans2,u,k);        u = f[u][k];    }    if(u==v) return make_pair(ans1,ans2);    for(int k=D;k>=0;k--) if(f[u][k] ^ f[v][k])    {        merge(ans1,ans2,u,k); u=f[u][k];        merge(ans1,ans2,v,k); v=f[v][k];    }    merge(ans1,ans2,u,0); merge(ans1,ans2,v,0);    return make_pair(ans1,ans2);}void init(){    scanf("%d%d",&n,&m);    memset(head,-1,sizeof(head));    maxedge=-1;    for(int i=1;i<=n;i++) fa[i]=i;    for(int i=1;i<=m;i++) scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].c);    sort(road+1,road+m+1);    MST=kruskal();    dfs(1,-1,0);}LL work(){    LL subMST=INF;    for(int i=1;i<=m;i++) if(!used[i])    {        pair <int,int> tmp = query(road[i].u,road[i].v);        if(road[i].c ^ tmp.first) smin(subMST,MST - tmp.first + road[i].c);        else smin(subMST,MST - tmp.second + road[i].c);    }    return subMST;}int main(){    #ifndef ONLINE_JUDGE    freopen("unique.in","r",stdin);    freopen("unique.out","w",stdout);    #endif    init();    printf(AUTO,work());    return 0;}
0 0
原创粉丝点击